十、java_IO
目录:
一、java流式输入/输出原理
java中,对于数据的输入/输出操作以”流”(Stream)方式进行;JDK提供了各种各样的”流”类,用以获取不同类型的数据;程序中通过标准的方法输入或输出数据
二、java流类的分类
- 按数据流的方向不同可以分为输入流和输出流
- 按处理数据单位不同可以分为字节流和字符流
- 按照功能不同可以分为节点流和处理流
jdk所提供的所有流类型位于包java.io内,分别继承自以下四种抽象流类型
字节流 | 字符流 | |
输入流 | InputStream | Reader |
输出流 | OutputStrean | Writer |
节点流:可以从一个特定的数据源(节点)读写数据(如:文件、内存)
处理流:是链接已存在的流(节点流或处理流)纸上,通过对数据的处理为程序提供更为强大的读写功能
三、输入/输出流类
1.InputStream
继承自InputStream的流都是用于向程序中输入数据,且数据的单位为字节(8bit);下图中神色为节点流,浅色为处理流
InputSream的基本方法:
//读取一个字节并以整数的形式返回(0-255),如果返回-1则已经到输入流的末尾 int read() throws IOException
//读取一系列字节并存储到一个数组buffer,返回实际读取的字节数。如果读取前已经到输入流的末尾返回-1 int read(byte[] buffer) throws IOException
//读取length个字节,并存储到一个字节数组buffer,从length位置开始,返回实际读取的字节数,如果读取前已经到输入流的末尾返回-1 int read(byte[] buffer, int offset, int length) throws IOException
//关闭流释放内存资源 void close() throws IOException
//跳过n个字节不读,返回实际跳过的字节数 long skip(long n) throws IOException
2.OutputStream
继承自OutPutStream的流是用于程序输出数据,且数据的单位为字节(8bit);下图中神色为节点流,浅色为处理流
OutputStream的基本方法:
//向输出流中写入一个字节数据,该字节数据为参数b的低8位 void write(int b) throws IOException
//将一个字节类型的数组中的数据写入输出流 void write(byte[] b) throws IOException
//将一个字节类型的数组中的从指定位置(off)开始的len个字节写入到输出流 void write(byte[] b, int off, int len) throws IOException
//关闭流释放内存资源 void close() throws IOException
//将输出流中还从的数据全部写入到目的地 void flush() throws IOException
3.Reader
继承自Reader的流都是用于向程序中输入数据,且数据的单位为字符(16bit);下图中神色为节点流,浅色为处理流
Reader的基本方法:
//读取一个字符并以整数的形式返回(0-255),如果返回-1则已经到输入流的末尾 int read() throws IOException //读取一系列字符并存储到一个数组buffer,返回实际读取的字符数。如果读取前已经到输入流的末尾返回-1 int read(char[] buffer) throws IOException //读取length个字符,并存储到一个字符数组buffer,从length位置开始,返回实际读取的字符数,如果读取前已经到输入流的末尾返回-1 int read(char[] buffer, int offset, int length) throws IOException //关闭流释放内存资源 void close() throws IOException //跳过n个字符不读,返回实际跳过的字符数 long skip(long n) throws IOException
4.Writer
继承自writer的流都是用于程序中输出数据,且数据的单位为字符(16bit);下图中神色为节点流,浅色为处理流
Writer常用方法
//向输出流中写入一个字符数据,该字符数据为参数b的低16位 void write(int b) throws IOException //将一个字符类型的数组中的数据写入输出流 void write(char[] b) throws IOException //将一个字符型的数组中的从指定位置(off)开始的len个字符写入到输出流 void write(char[] b, int off, int len) throws IOException //将一个字符串中的字符写入到输出流 void wrete(String string) throws IOException //将一个字符串从offset开始的length个字符写入到输出流 void write(String string, int offset, int length) throws IOException //关闭流释放内存资源 void close() throws IOException //将输出流中还从的数据全部写入到目的地 void flush() throws IOException
四、常见的节点流和处理流
1.节点流类型:
2.处理流类型:
五、文件流
FileInputStream和FileOutputStream分别继承自InputStream和OutputStream用于向文件中输入和输出字节
FileInputStream和FileOutputStream常用构造方法:
FileInputStream(String name) throws FileNotFoundException FileInputStream(File file) throws FileNotFoundException FileOutputStream(String name) throws FileNotFoundException FileOutputStream(File file) throws FileNotFoundException FileOutputStream(File file,boolean append) throws FileNotFoundException
FileInputStream和FileOutputStream类支持其父类InputStream和OutputStream所提供的数据读写方法。
注意:
- 在实例化FileInputStream和FileOutputStraeam流时要用try-catch语句来处理其可能抛出的FileNotFoundException
- 在读写数据时也要用try-catch语句来处理可能抛出IOException
- FileNotFoundException是IOException的子类
FileInputStream:
public class Test{ public static void main(String[] args) { int b = 0 ; FileInputStream in = null; //打开文件 try { in = new FileInputStream("F:\\test.txt");//windows下路径分隔符是两个反斜杠,也可以直接使用正斜杠 } catch (FileNotFoundException e) { System.out.println("找不到指定文件"); System.exit(-1); } //读取文件 try { long num = 0; while((b = in.read()) != -1) { System.out.print((char)b); num++; } in.close(); System.out.println(); System.out.print("共读取了 "+ num +" 个字节"); } catch (IOException e1) { System.out.println("文件读取错误"); System.exit(-1); } } }
FileOutputStream:
public class Test{ public static void main(String[] args) { int b = 0 ; FileInputStream in = null; FileOutputStream out = null; //打开文件 try { in = new FileInputStream("F:\\test.txt");//windows下路径分隔符是两个反斜杠,也可以直接使用正斜杠 out = new FileOutputStream("F:/test1.txt");//如果目录下没有这个文件FileOutputStream会自动生成一个 while((b = in.read()) != -1) { out.write(b);//一个个字节写进去 } in.close();//管道用完记得关闭 out.close(); } catch (FileNotFoundException e) { System.out.println("找不到指定文件"); System.exit(-1); } catch (IOException e1) { System.out.println("文件复制错误"); System.exit(-1); } System.out.print("复制成功"); } }
FileReader:
public class Test{ public static void main(String[] args) { FileReader fr = null; int c = 0; try { fr = new FileReader("f:/test.txt"); int in = 0; while ((c = fr.read()) != -1) { System.out.print((char)c); } } catch (FileNotFoundException e) { System.out.print("找不到指定文件"); } catch (IOException e1) { System.out.print("文件读取错误"); } } }
FileWriter:
public class Test{ public static void main(String[] args) { FileReader fr = null; FileWriter wr = null; int c = 0; try { fr = new FileReader("f:/test.txt"); wr = new FileWriter("f:/test1.txt"); int in = 0; while ((c = fr.read()) != -1) { wr.write(c); } wr.close(); fr.close(); } catch (FileNotFoundException e) { System.out.print("找不到指定文件"); } catch (IOException e1) { System.out.print("文件写入错误"); } } }
六、缓冲流
缓冲流要”套接”在相应的节点流纸上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法
JDK提供了四种缓冲流,其常用的构造方法为:
BufferedReader(Reader in) BufferedReader(Reader in,int sz)//sz为自定义缓冲区的大小 BufferedWriter(Writer out) BufferedWriter(Writer out,int sz) BufferedInputStream(InputStream in) BufferedInputStream(InputStream in, int sz) BufferedOutputStream(OutputStream out) BufferedOutputStream(OutputStream out, int sz)
- 缓冲流输入支持其父类的mark和reset方法
- BufferedReader提供了readLine方法用于读取一行字符串(以\r 或\n分割)
- BufferedWriter提供了newLine用于写入一个行分隔符
- 对于输出的缓冲流,写出的数据会现在内存中缓存,使用flush方法将会使内存中的数据立刻写出
BufferStream1:
public class Test{ public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("f:/test.txt"); BufferedInputStream bis = new BufferedInputStream(fis);//相当于管道套管道,为了使用缓冲区的功能 int c = 0; System.out.println((char)bis.read()); System.out.println((char)bis.read()); bis.mark(100);//从100个开始往外读 for(int i=0; i<10 && (c=bis.read()) != -1; i++) { System.out.print((char)c + " "); } System.out.println(); bis.reset();//回到100的那个点上 for(int i=0; i<=10 && (c=bis.read()) != -1; i++) { System.out.print((char)c + " "); } bis.close(); } catch(IOException e) { e.printStackTrace(); } } }
BufferStream2:
public class Test{ public static void main(String[] args) { try { BufferedWriter bw = new BufferedWriter(new FileWriter("f:/test.txt"));//管道套接 BufferedReader br = new BufferedReader(new FileReader("f:/test.txt")); //写入 String s = null; for(int i=1; i<100; i++) { s = String.valueOf(Math.random());//产生一个字符串的随机数 bw.write(s);//写一个字符串到缓冲区 bw.newLine();//写一个换行到缓冲区 } bw.flush();//将缓存内存中的数据写出 //逐行读取 while((s=br.readLine()) != null) { System.out.println(s); } bw.close(); br.close(); } catch(IOException e) { e.printStackTrace(); } } }
七、数据流
- DataInputStream和DataOutPutStream分别继承自InputStream和OutPutStream,它属于处理流,需要分别”套接”在InputStream和OutputStream类型的节点流上
- DataInputStream和DataOutputStream提供了可以存取与机器无关的java原始类型数据(如:int,double等)的方法
- DataInputStream和DataOutputStream的构造方法为:
DataInputStream(InputStream in)
DataOutputStream(OutputStream out)
看一个例子:
public class Test{ public static void main(String[] args) { ByteArrayOutputStream baos = new ByteArrayOutputStream();//在内存中分配字节数组 DataOutputStream dos = new DataOutputStream(baos);//套接 try { dos.writeDouble(Math.random());//写一个double类型的随机数,double是8个字节 dos.writeBoolean(true);//写一个布尔值进去,布尔值在内存中只占一个字节 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());//读数据,只能一个字节一个字节读 System.out.println(bais.available());//输出字节数 DataInputStream dis = new DataInputStream(bais);//套接 System.out.println(dis.readDouble());//输出数据1,注意,先写的先读 System.out.println(dis.readBoolean());//输出数据2 dos.close(); dis.close(); } catch(IOException e) { e.printStackTrace(); } } }
八、转换流
- InputStreamReader和OutputStreamWriter用于字节数据到字符数据之间的转换
- InputStreamReader需要和InputStream”套接”
- OutputStreamWriter需要和OutputStream”套接”
- 转换流在构造时可以指定其编码集合,例如:InputStream isr = new InputStreamReader(System.in, “ISO8859_1”)
OutputStreamWriter:
public class Test{ public static void main(String[] args) { try { OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("f:/test.txt")); osw.write("aaa"); System.out.println(osw.getEncoding()); //获取osw的字符编码 osw.close(); //true表示在原文件的基础上追加,如果不加true,则会删除原文件的内容后再写入新的内容,ISO8859_1是一种字符编码,指定了要写入内容的编码格式 osw = new OutputStreamWriter(new FileOutputStream("f:/test.txt", true), "ISO8859_1"); osw.write("bbb"); System.out.println(osw.getEncoding()); osw.close(); } catch (IOException e) { e.printStackTrace(); } } }
InputStreamReader:
/* * 这个程序相当于一直逐行读取键盘输入,直到输入exit为止,这是一种阻塞式的方法,程序运行起来后不输入exit程序就一直停在那,也可以理解为是同步式的 */ public class Test{ public static void main(String[] args) { InputStreamReader isr = new InputStreamReader(System.in);//System.in是接收的键盘输入 BufferedReader br = new BufferedReader(isr); String s = null; try { s = br.readLine(); //除非s="exit"否则就不停的读 while(s != null) { if(s.equalsIgnoreCase("exit")) { break; } else { System.out.println(s.toUpperCase()); s = br.readLine(); } } br.close(); } catch (IOException e) { e.printStackTrace(); } } }
九、Print流
- PrintWriter和PrintStream都属于输出流,分别针对与字符和字节
- PrintWriter和PrintStream提供了重载的print
- Println方法用于多种数据类型的输出
- PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息
- PrintWriter和PrintStream有子的佛那个flush功能
PrintWriter(Writer out) PrinWriter(Writer out,boolean autoFlush) PrintWriter(OutputStream out) PrintWriter(PutputStream out, boolean autoFlush) PrintStream(OutputStream out) PrintStream(OutputStream out, boolean autoFlush)
例子1:
public class Test{ public static void main(String[] args) { PrintStream ps = null; try { FileOutputStream fos = new FileOutputStream("f:/test.txt"); ps = new PrintStream(fos);//套接 } catch(IOException e) { e.printStackTrace(); } if(ps != null) { System.setOut(ps);//更改默认输出位置为ps,System.out默认指向的是控制台 } int ln = 0; for(char c=0; c<=60000; c++) { System.out.print(c+" "); if(ln++ >= 100) { System.out.println(); ln = 0; } } } }
例子2:
public class Test{ public static void main(String[] args) { String filename = args[0];//外部传参 if(filename != null) { list(filename,System.out); } } public static void list(String f,PrintStream fs){ try { BufferedReader br = new BufferedReader(new FileReader(f)); String s = null; //按行读取 while((s=br.readLine()) != null) { fs.println(s); } br.close(); } catch(IOException e) { fs.println("无法读取文件"); } } }
例子3:
public class Test{ public static void main(String[] args) { String s = null; BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//System.in是键盘输入 try { FileWriter fw = new FileWriter("f:/test.txt",true);//true追加在原文件后面 PrintWriter log = new PrintWriter(fw); while((s=br.readLine()) != null){ if(s.equalsIgnoreCase("exit")){ break;//如果键盘输入exit则停止运行 } System.out.println(s.toUpperCase());//控制台输出 log.println("----"); log.println(s.toUpperCase());//写入 log.flush(); } log.println("==="+new Date()+"===");//new Date()指的是util里的date,也就是当前时间 log.flush(); log.close(); } catch(IOException e) { e.printStackTrace(); } } }
十、Ubject流
作用:直接将Object写入或读出
- transient关键字
- serializable接口 标记类里的对象可以序列化
- externalizable接口 控制类的对象是怎么写出去的,也就是说可以自己控制序列化过程
看一个例子:
class T implements Serializable{//如果要写入或者读对象必须要实现Serializable接口,这是一个标记接口,所以不需要重写方法 int i = 0; int j = 9; double d = 2.3; int k = 0; }
public class Test{ public static void main(String[] args) throws Exception{ T t = new T(); t.k = 8; FileOutputStream fos = new FileOutputStream("f:/test.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(t);//把t对象写入f:/test.txt oos.flush(); oos.close(); FileInputStream fis = new FileInputStream("f:/test.txt"); ObjectInputStream ois = new ObjectInputStream(fis); T tReaded = (T)ois.readObject();//读对象 System.out.println(tReaded.i+" "+tReaded.j+" "+tReaded.d+" "+tReaded.k); } }
上面例子中的输出结果为:0 9 2.3 8
如果将T里的 int k = 0; 改为 transient int k = 0;
则输出结果应该是0 9 2.3 0
因为transient相当于把k变成了透明的,使用transient修饰的成员变量在序列化(操作对象)的时候不予考虑
- 本文为博主学习笔记,未经博主允许不得转载
- 本文仅供交流学习,请勿用于非法途径
- 本文仅是个人意见,如有想法,欢迎交流