11、流与文件
一、概述
import java.io.File;
import java.io.FileOutputStream;
java中所有的基本I/O操作都是流(stream)为基础的。流代表数据的流动或一端的写入器与另一端的读取器相互通信的通道。
在使用终端的输入输出设备,正在读或写文件,或者在Java中通过套接字(socket)进行通信时,我们就已经使用了某种类型的流。
按照流处理的数据类型,可以分为:
-字节流:用于处理字节数据。
XXXInputStream
XXXOutputStream
-字符流:用于处理Unicode字符数据
XXReader
XXWriter
两种基本的流:输入流和输出流(参照物:内存)
写入和读出参照的是硬盘。
写入对应输出,读出对应输入。
-输入流:只能从中读取字节数据,而不能向其写出数据 。读取文件
-输出流:只能向其写入字节数据,而不能从中读取数据。保存文件
二、常见的InputStream类
低级的InputStream类
-抽象类:InputStream
-ByteArrayInputStream
-PipedInputStream
-FileInputStream
高级的InputStream
-DataInputStream
-BufferedInputStream
四、输出流FileOutputStream(字节流输出写入)类的具体用法
导入java.io.File包
java.io.FileOutputStream
为了能让finally中也能获取到FileOutputStream的实例化的对象,一种方法是让定义在try外进行,让实例化在try中进行;另一种方法是让定义实例化的整个过程在try后的小括号中进行,这种方法实现了closable接口,所以无需再次在finally中关闭。
fos.write(“北京”.getBytes(),true);先将字符变成字节,后面为真,则北京写在了文件末尾,而不是刷新了文件再写北京了。
五、输入流FileInputStream(字节流输入读出)类的具体用法
导入java.io.File;包, File file=new File("456.txt");
利用了buffer缓存数组来将内存中的数据先缓存到数组中,然后再输出到显示器中。
public void read(){ File file=new File("src/com/zxc/k/456.txt"); try(FileInputStream fis=new FileInputStream(file)){ byte buffer[]=new byte[(int)file.length()]; fis.read(buffer);//读到缓存中 System.out.println(new String(buffer).trim()); }catch (Exception e){ e.printStackTrace(); } }
六、字节流复制
利用缓存,buffer。先读后写。利用System.currentTimeMillis()记录开始和结束的时间,来算出总共复制所需时间。
fis.read(buffer)的返回值是一个int,当为-1时候则为输入结束读取结束。
public void copy(){//先读后写 long start=System.currentTimeMillis(); try(FileInputStream fis=new FileInputStream("d://456.txt"); FileOutputStream fos=new FileOutputStream("src/com/zxc/k/456.txt",true)){ byte buffer[]=new byte[1024*1024*1024]; int n=0; while ((n=fis.read(buffer))!=-1){ fos.write(buffer,0,n); } }catch (Exception e){ e.printStackTrace(); }finally { long end = System.currentTimeMillis(); long time=end-start; System.out.println(time); } }
七、字符流输出输入
import java.io.Reader;
import java.io.FileReader;
其中的try括号中Reader r=new FileReader("D://456.txt");体现了多态特性,FileReader是Reader的父类。
package com.zxc.K; import org.junit.Test; import java.io.*; /** * Created by Administrator on 2018/2/5 0005. */ public class B { @Test public void read(){ File file=new File("d://456.txt"); try(Reader r=new FileReader("d://456.txt")){ char buffer[]=new char[(int)file.length()]; r.read(buffer); System.out.println(new String(buffer).trim()); }catch(Exception e){ e.printStackTrace(); } } @Test public void write(){ try(Writer out=new FileWriter("d://456.txt")){ out.write("成都"); }catch (Exception e){ e.printStackTrace(); } } @Test public void copy(){ try(Reader reader=new FileReader("d://456.txt"); Writer writer=new FileWriter("e://456.txt")){ char []buffer=new char[1024]; int n=0; while((n=reader.read(buffer))!=-1){ writer.write(buffer,0,n); } }catch(Exception e){ e.printStackTrace(); } } }
其中复制中的write()方法必须使用三个参数,如果不使用,会出现大量null乱码字符
八、缓冲流
自带4096字节缓存,不用再定义缓存。
package com.zxc.K; import org.junit.Test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; /** * Created by Administrator on 2018/2/5 0005. */ public class C { @Test public void copy() { try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d://456.txt")); BufferedOutputStream bos= new BufferedOutputStream(new FileOutputStream("e://456.txt"))) { int n=0; byte buffer[]=new byte[1024*4]; while((n=bis.read(buffer))!=-1){ bos.write(buffer,0,n); } } catch (Exception e) { e.printStackTrace(); } } }
九、转换流
输入输出流体系里还提供了两个转换流,这两个转换流用于实现将字节流转换成字符流,其中InputStreamReader将字节输入流转换成字符输入流,OutputStreamWriter将字节输出流转换成字符输出流。
@Test不能用在交互的System.in中
package com.zxc.K; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Scanner; /** * Created by Administrator on 2018/2/5 0005. */ public class D { public static void test2(){ Scanner sc=new Scanner(System.in); while(true){ String s=sc.nextLine(); if(s.toUpperCase().equals("Q")){ break; } System.out.println(s); } } public static void test3(){ InputStream is=System.in; BufferedReader br=new BufferedReader(new InputStreamReader(is)); try{ String s=br.readLine(); System.out.println(s); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { test3(); } }
十、序列化Serializable
对象序列化的目标是将一个对象保存在磁盘中,或允许在网络中直接传输对象,对象序列化机制允许把内存中的java对象转换成平台无关的二进制流,从而允许把这种二进制流持久保存在磁盘中,通过网络将这种二进制流传输到另一个网络节点。(就是将内存中存的java对象转换成二进制进而长久存放在硬盘或者从网络传出去)
该机制使得对象可以脱离程序的运行而独立存在。
对象的序列化(Serialize)指将一个Java对象写入IO流中,与此对应的是,对象的反序列化(DeSerialize)则指从IO流中回复该Java对象。
因此如果让某个类可以支持序列化机制,必须让类是可序列化的,也就是要实现Serializable接口或Externalizable(反序列化)接口
序列化注意事项:
1、静态的属性不会被序列化
2、对象的类名、属性都会被序列化,方法不会被序列化
3、要保证序列化对象所在类的属性也是可以被序列化的
4、当通过网络、文件进行序列化时,必须按照写入顺序读取对象。
5、反序列化时必须有序列化对象时的class文件
6、最好显示的声明serializableID,因为在不同的JVM之间,默认生成的ID可能不同,会造成反序列失败。
常见的序列化协议:
COM:主要用于windows平台,并没有实现跨平台。
CORBA:是早期比较好的实现了跨平台,跨语言的序列化协议,使用复杂。
XML&SOAP:XML是一种常用的序列化和反序列化协议,具有跨机器,跨语言等优点。
SOAP(Simple Object Access protocol):是一种被广泛应用的,基于XML为序列化和反序列haul协议的结构化消息传递协议。SOAP具有安全、可扩展、跨语言、跨平台并支持多种传输层协议;
JSON(Javascript Object Notation):js对象符号
十一、File类
java.io.File;
isFile() 判断是否为文件
isDirectory()判断是否为目录
isAbsolute()判断是否为绝对路径
getName()返回名字
getPath() 返回路径
getAbsolutePath()返回绝对路径
getParent()返回父目录
createNewFile()创建新文件
delete()删除目录或文件
exists()判断是否存在
length()长度
listfiles()返回文件对象数组 返回目录中的东西
public class E { public static void main(String[] args) { new E().listFiles("D://HSA"); } public static void listFiles(String path) { File file = new File(path); File fs[] = file.listFiles(); if (fs != null) { for (File f : fs) { if (f.isDirectory()) { listFiles(f.getPath()); } else { System.out.println(f.getAbsoluteFile()); } } } } }