IO流
输入输出流分类
java,io定义了多个流类型来实现输入/输出功能,从不同角度分类如下:
- 按数据流方向不同分为:输入流,输出流
- 按处理的数据单位不同分为:字节流,字符流
- 按功能不同分为:节点流和处理流
字节流:最原始的流,按照字节来读。一个字节(Byte)是8位(bit)。
字符流:字符流是一个字符一个字符的读取数据,一个字符是2个字节。
所有流类型都位于java.io包中,分别继承自四种抽象类类型:
- 输入流:InputStream(字节流),Reader(字符流)
- 输出流:OutputStream(字节流),Writer(字符流)
输入输出流是站在程序的角度来说的
节点流和处理流
节点流类型
类型 | 字符流 | 字节流 |
File(文件) |
FileReader,FileWriter |
FileInputStream,FileOutputStream |
Memory Array |
CharArrayReader,CharArrayWriter |
ByteArrayInputStream,ByteArrayOutputStream |
Memory String | StringReader,StringWriter | - |
Pipe(管道) | PipedReader,PipedWriter | PipedInputStream,PipedOutputStream |
处理流类型
处理类型 | 字符流 | 字节流 |
Buffering | BufferedReader,BufferedWriter | BufferedInputStream,BufferedOutputStream |
Filtering | FilterReader,FilterWriter | FilterInputStream,FilterOutputStream |
Converting between bytes and character | InputStreamReader,OutputStreamWriter | - |
Object Serialization | - | ObjectInputStrem,ObjectOutputStream |
Data conversion | DataInputStream,DataOutputStream | |
Counting | LineNumberReader | LineNumberInputStream |
Peeking ahead | PushbackReader | PushbackInputStream |
Printing | PrintWriter | PrintStream |
InputStream(输入流)
public class JavaTest { public static void main(String[] args) throws IOException { //读取中文是乱码,因为其是一个字节一个字节读取的,而汉字占用两个字节,所以读取出来的汉字无法正确显示 FileInputStream in =null; try{ in=new FileInputStream("F:\\Java笔记\\test.txt"); } catch (FileNotFoundException e) { System.out.println("找不到文件"); e.printStackTrace(); System.exit(-1); } long num=0;//存放读取到字节数 int b=0;//存放调用read的返回值 try{ //read()读取到输入流末尾就返回-1 while((b=in.read())!=-1){ //b是read()方法返回的0-255的数字,强制转换为char类型才能显示成英文 System.out.println((char)b); num++; } }catch(IOException e1){ System.out.println("读取出错"); }finally { //关闭流,释放内存资源 in.close(); } } }
OutputStream(输出流)
public class JavaTest { public static void main(String[] args) throws IOException { //读取中文是乱码,因为其是一个字节一个字节读取的,而汉字占用两个字节,所以读取出来的汉字无法正确显示 FileInputStream in =null; FileOutputStream out=null; try{ in=new FileInputStream("F:\\Java笔记\\test.txt"); out=new FileOutputStream("F:\\Java笔记\\cpye_test.txt");//没有文件会自己创建文件 } catch (FileNotFoundException e) { System.out.println("找不到文件"); e.printStackTrace(); System.exit(-1); } int b=0;//存放调用read的返回值 try{ //read()读取到输入流末尾就返回-1 while((b=in.read())!=-1){ out.write(b); } }catch(IOException e1){ System.out.println("文件复制失败"); System.exit(-1); }finally { //关闭流,释放内存资源 in.close(); out.close(); } } }
Reader流
和InputStream一样,区别就是读取的数据单位不同
Writer流
和OutputStream一样,区别就是数据的单位是字符
public class JavaTest { public static void main(String[] args) throws IOException { FileWriter fw=null; FileReader fileReader=null; try{ fw=new FileWriter("F:\\Java笔记\\test.txt"); for(int i=0;i<1000;i++){ fw.write(i); } int b=0; long num=0; fileReader=new FileReader("F:\\Java笔记\\test.txt"); while((b=fileReader.read())!=-1){ System.out.println((char)b); num++; } System.out.println("读取了"+num); }catch(Exception e){ e.printStackTrace(); }finally { fw.close(); fileReader.close(); } } }
处理流
节点流就是直接和数据源连接的流,处理流就是套接在其他流上的流,处理流不直接和数据源连接
缓冲流(Buffering)
缓冲流要套接在相应的节点流之上,对读写的数据提供缓冲功能,提高读写得效率,有4种缓冲流,对应构造方法如下:
BufferedReader(Reader in) BufferedReader(Reader in,int size)//size为自定义的缓冲区大小 BufferedWriter(Writer out) BufferedWriter(Writer out,int size) BufferedInputStream(InputStream in) BufferedInputStream(InputStream in,int size) BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out,int size)
对于输出的缓冲流,写的数据会先在内存中缓存,使用flush()方法将会使内存中的数据立刻写入。
读写数据时,先把数据放到缓冲区里,减少IO对硬盘的访问次数。
public class JavaTest { public static void main(String[] args) throws IOException { FileInputStream in=null; try{ in =new FileInputStream("F:\\Java笔记\\test.txt"); //在FileInputStream节点流外在套一层处理流 BufferedInputStream bf=new BufferedInputStream(in); int c=0; System.out.println((char)bf.read()); System.out.println((char)bf.read()); System.out.println("======="); bf.mark(20);//加标记 for(int i=0;i<=10&&(c=bf.read())!=-1;i++){ System.out.println((char)c); } System.out.println("========"); bf.reset();//回到标记处 for(int i=0;i<10&&(c=bf.read())!=-1;i++){ System.out.println((char)c); } bf.close(); }catch (FileNotFoundException e){ e.printStackTrace(); }catch (Exception e1){ e1.printStackTrace(); } } }
BufferedReader,BufferedWriter
public class JavaTest { public static void main(String[] args) throws IOException { try { FileWriter fileWriter = new FileWriter("F:\\Java笔记\\copy_test.txt"); BufferedWriter bw=new BufferedWriter(fileWriter); String s=null; for(int i=0;i<100;i++){ s=String.valueOf(Math.random()); bw.write(s); bw.newLine();//换行 } bw.flush(); BufferedReader br=new BufferedReader(new FileReader("F:\\Java笔记\\copy_test.txt")); while((s=br.readLine())!=null){ System.out.println(s); } bw.close(); br.close(); }catch (Exception e){ e.printStackTrace(); } } }
转换流
InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换,InputStreamReader需要和InputStream套接,OutputStreamWriter需要和OutputStream套接。转换流在构造时可以指定编码集
public class JavaTest { public static void main(String[] args) throws IOException { try{ OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("F:\\Java笔记\\test.txt")); osw.write("wjzzu,wsdsb"); System.out.println(osw.getEncoding());//获得当前字符编码 osw=new OutputStreamWriter(new FileOutputStream("F:\\Java笔记\\test1.txt",true),"ISO8859_1");//在文件后追加,并指定编码 System.out.println(osw.getEncoding()); osw.close(); }catch (Exception e){ e.printStackTrace(); } } }
数据流
DataInputStream和DataOutputStream分别继承自InputStream和OutputStream,提供可以存取与机器无关的java原始数据类型(int,double)等方法
public static void main(String[] args) throws IOException { ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();//在内存里创建一个字节数组 DataOutputStream dataOutputStream=new DataOutputStream(byteArrayOutputStream); try{ dataOutputStream.writeDouble(Math.random());//把随机double类型的数写入到字节数组中 dataOutputStream.writeBoolean(false); ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); System.out.println(byteArrayInputStream.available());//获取字节数组有几个字节 DataInputStream dataInputStream=new DataInputStream(byteArrayInputStream); System.out.println(dataInputStream.readDouble()); System.out.println(dataInputStream.readBoolean()); dataInputStream.close(); dataOutputStream.close(); }catch (Exception e){ e.printStackTrace(); } } }
注:读取的数据是先写进去的先被读取
打印流
PrintStream和PrintWriter都是打印流,分别针对字节和字符
PrintStream和PrintWriter分别提供了重载的print
Println方法用于多种类型的输出
PrintStream和PrintWriter有自动flush功能,
PrintStream和PrintWriter不会抛出异常,通过检测错误状态来获取错误信息
public class JavaTest { public static void main(String[] args) throws IOException { PrintStream ps=null; try{ FileOutputStream fos=new FileOutputStream("F:\\Java笔记\\print.txt"); ps=new PrintStream(fos); if(ps!=null){ System.setOut(ps);//将打印输出窗口连接到流,在文件里输出 } for(char c=0;c<=100;c++){ System.out.println(c); } }catch(Exception e){ e.printStackTrace(); } } }
对象流
直接将Object写入或读入
对象序列化:
- transient关键字:用它来修饰的成员变量在序列化的时候不考虑,即当做不存在(默认值)
- serializable接口:标记型接口
- externalizable接口
public static void main(String[] args) throws IOException { T t =new T(); t.k=8; try{ FileOutputStream fos=new FileOutputStream("F:\\Java笔记\\test2.txt"); ObjectOutputStream ojs=new ObjectOutputStream(fos); ojs.writeObject(t); ojs.flush(); ojs.close(); FileInputStream fis=new FileInputStream("F:\\Java笔记\\test2.txt"); ObjectInputStream ois=new ObjectInputStream(fis); T t1=(T)ois.readObject(); System.out.println(t1.d+"\t"+t1.k); ois.close(); }catch(Exception e){ e.printStackTrace(); } } public class T implements Serializable { int j=10; int i=9; double d=2.3; int k=15; }
直接实现Serializable接口的类是JDK自动把这个类的对象序列化,而实现Externalizable接口的类是自己控制对象序列化。