Java入门——IO(输入与输出)
Posted gdwkong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java入门——IO(输入与输出)相关的知识,希望对你有一定的参考价值。
IO流位于java.io包中,根据操作数据不同,分为字节流和字符流;根据数据输入方面的不同又可分为输入流和输出流,无论是何种流,最终都依赖于操作系统。
一、字节流:
1、字节流,主要用于图片、音频、视频的传输,以二进制的形式进行,分为字节输入流和字节输出流;字节流操作的是字节数组;字符流操作的是字符数组。
2、字节输入与字节输出流的继承体系图
3、InputStream 与OutputStream常用方法
InputStream 常用方法
|
|
方法声明
|
功能描述
|
int read()
|
从输入流读取一个8位的字节,把它转换为0-255之间的整数,并返回这一整数
|
int read(byte[] b)
|
从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取的字节数
|
int read(byte[] b,int off,len)
|
从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节
|
void close()
|
关闭此输入流并释放与该流关联的所有系统资源
|
OutputStream 常用方法
|
|
方法声明
|
功能描述
|
void write(int b)
|
向输出流写入一个字节
|
void write(byte[] b)
|
把参数b指定的字节数组的所有字节写到输出流
|
void write(byte[] b,int off,len)
|
将指定byte数组中从偏移量off开始的len个字节写入输出流
|
void flush()
|
刷新此输出流并强制写出所有缓冲的输出字节
|
void close()
|
关闭此输出流并释放与该流关联的所有系统资源
|
4、字节流读写文件:
FileInputStream 是操作文件的的字节输入流,专门用于读取文件中的数据。
FileOutputStream是操作文件的的字节输出流,专门用于把数据写入文件。
示例:
1 public class Example01 { 2 public static void main(String[] args) throws Exception{ 3 //创建一个文件字节型输入流 4 InputStream inputStream = new FileInputStream("test.txt"); 5 int b = 0; //定义一个int类型的变量b,记住每一次读取的一个字节 6 while (true){ 7 b=inputStream.read();//变量b记住读取的一个字节 8 if(b==-1){ //如果读取的字节为-1,跳出while循环 9 break; 10 } 11 System.out.println(b); //否则将b写出 12 } 13 inputStream.close(); 14 15 //创建一个文件字节输出流 16 OutputStream OutputStream= new FileOutputStream("example.txt",true); 17 String string = "人之初"; 18 byte [] bytes= string.getBytes(); 19 for (int i = 0;i<bytes.length;i++){ 20 OutputStream.write(bytes[i]); 21 } 22 OutputStream.close(); 23 } 24 }
文件拷贝:
1 public class Example04 { 2 public static void main(String[] args) throws Exception{ 3 //创建一个字节输入流,用于读取当前目录下source文件中的docx文件 4 InputStream in = new FileInputStream("source/IO工具包.mp4") ; 5 //创建一个文件字节输出流,用于将读取的数据写入target目录下的文件中 6 OutputStream out = new FileOutputStream("target/IO工具包.mp4"); 7 byte [] buff = new byte[1024]; //定义一个字节数组,作为缓冲区 8 int len; //定义一个int类型的变量len记住读取读入缓冲区的字节数 9 // int len = 0 ; //定义一个int类型变量,记住每次读取的一个字节 10 long begintime = System.currentTimeMillis(); 11 while ((len=in.read(buff))!=-1){ //判断是否读到文件末尾 12 out.write(buff,0,len); //从第一字节开始,向文件写入len个字节 13 } 14 long endtime = System.currentTimeMillis(); 15 System.out.println("耗时"+(endtime-begintime)+"毫秒"); 16 in.close(); 17 out.close(); 18 } 19 }
5、装饰设计模式思想:
TextReader:读取文本;MediaReader:读取媒体数据;抽取共性,形成体系。Reader|---TextReader read()|---MediaReader需求1:提高读取文本的效率,使用缓冲技术,提供一个读取文本更高效的读取方法。覆盖TextReader中的方法。建立高效的read方法。所以建立一个TextReader的子类,用于高效的读取。Reader|---TextReader read()|--BufferedTextReader|---MediaReader需求2:提高读取媒体数据的效率,派生一个高效的子类,用于高效的读取。Reader|---TextReader read()|--BufferedTextReader|---MediaReader|--BufferedMediaReader发现一个小问题,如果Reader中还有读取其他数据的子类,如果要高效,那岂不是还要给这个子类添加一个高效子类?是的,为了给具体的读取数据的对象增加一些功能,是需要通过子类来完成的。但是这样做,会导致这个继承体系很臃肿!仅仅为了增加一些功能,而进行继承,不建议的。这些子类无非就是需要高效,而且这些高效的功能实现是一致的。就是提供一个缓冲区而以。干脆,单独定义一个具备这个缓冲功能的对象,哪个子类需要被缓冲,就将哪个子类传递进来。class BufferedReader extends Reader{private [];//提供数据BufferedReader(Reader r){ //对Reader高效就行}read(){操作的是数组} //高效的读取动作}此时继承体系:Reader|---TextReader|---MediaReader|---BufferedReader发现这种设计方式减少了继承体系的臃肿,增减功能,比继承更为灵活。这种设计方式称为:装饰设计模式。解决问题:给一组类增加功能,避免继承的臃肿,提高灵活。注意:装饰类和被装饰类必须属于同一体系,通常装饰类都会提供构造函数接收被装饰类对象。装饰类通常不单独存在。
6、字节缓冲流
使用的是装饰设计模式
示例:
1 public class Example07 { 2 public static void main(String[] args) throws Exception{ 3 //创建一个带缓冲区的输入流 4 BufferedInputStream bis = new BufferedInputStream( 5 new FileInputStream("src.txt")); 6 //创建一个带缓冲区的输出流 7 BufferedOutputStream bos = new BufferedOutputStream( 8 new FileOutputStream("des.txt")); 9 int len; 10 while ((len=bis.read())!=-1){ 11 bos.write(len); 12 } 13 bis.close(); 14 bos.close(); 15 } 16 }
二、字符流
1、字符流:为了便于操作数据中的字符数据。原理:字节流+编码表。
2、字符流继承体系
3、基类方法摘要
Reader方法摘要
|
|
abstract void close()
|
关闭该流并释放与之关联的所有资源。
|
void mark(int readAheadLimit)
|
标记流中的当前位置。
|
boolean markSupported()
|
判断此流是否支持 mark() 操作。
|
int read()
|
读取单个字符。
|
int read(char[] cbuf)
|
将字符读入数组。
|
abstract int read(char[] cbuf, int off, int len)
|
将字符读入数组的某一部分。
|
int read(CharBuffer target)
|
试图将字符读入指定的字符缓冲区。
|
boolean ready()
|
判断是否准备读取此流。
|
void reset()
|
重置该流。
|
long skip(long n)
|
跳过字符。
|
Writer方法摘要
|
|
void close()
|
关闭此流,但要先刷新它。
|
void flush()
|
刷新该流的缓冲。
|
String getEncoding()
|
返回此流使用的字符编码的名称。
|
void write(char[] cbuf, int off, int len)
|
写入字符数组的某一部分。
|
void write(int c)
|
写入单个字符。
|
void write(String str, int off, int len)
|
写入字符串的某一部分。
|
flush()和close()的区别?flush();将流中的缓冲区缓冲中的数据刷新到目的地中,刷新后,流还可以继续使用;close();关闭资源,但在关闭前会将缓冲区中的数据刷新到目的地,否则丢失数据,然后再关闭流,流不可以使用。如果写入数据多,一边写一边刷新,最后一次可以不刷新,由close()完成刷新并关闭。
4、字符流操作文件
FileReader 和FileWriter 用于读写文件;BufferedReader 和BufferdeWriter是具有缓冲功能的流,可以提高读写效率。
BufferedReader中有一重要的方法readLind(),该方法用于一次读取一行文本。
1 public class Example10 { 2 public static void main(String[] args) throws Exception{ 3 FileReader reader = new FileReader("src.txt"); 4 //创建一个BufferedReader缓冲对象 5 BufferedReader br = new BufferedReader(reader); 6 FileWriter writer = new FileWriter("des.txt"); 7 //创建一个BufferedWriter缓冲对象 8 BufferedWriter bw = new BufferedWriter(writer); 9 String string; 10 while ((string=br.readLine())!=null){ 11 bw.write(string); 12 bw.newLine();//写入一个换行符,该方法会根据不同的操作系统生成相应的换行符 13 } 14 br.close(); 15 bw.close(); 16 } 17 }
BufferedReader一直接子类——LineNumberReader ,一个可以跟踪行号的输入流。
1 public class Example11 { 2 public static void main(String[] args) throws Exception{ 3 FileReader fr = new FileReader("/Users/Shared/第八章IO练习/exampele09.txt"); //创建字符输入流 4 FileWriter fw = new FileWriter("copy.txt");//创建字符输出流 5 LineNumberReader lr = new LineNumberReader(fr); //包装 6 lr.setLineNumber(0); //设置读取文件的起始行号 7 String line = null; 8 while ((line=lr.readLine())!=null){ 9 fw.write(lr.getLineNumber()+":"+line);//将行号写入到文件中 10 fw.write("\\r\\n"); //写入换行 11 } 12 lr.close(); 13 fw.close(); 14 } 15 }
5、转换流
转换流是一种字符流,只能实现字节流读写文本数据的时候,通过转换流来使用字符高效流的方法。而不能实现图片、音频等数据的读写。
InputStreamReader:理解上是字节流通向字符流的桥梁,使用上为:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
OutputStreamWriter:理解上是字符流通向字节流的桥梁,使用上还是通过字节流转成字符流:
BufferedWriter bw = new BufferedWriter (new OutputStreamWriter(System.out));
1 public class Example12 { 2 public static void main(String[] args) throws Exception{ 3 FileInputStream in= new FileInputStream("src1.txt");//创建字节输入流 4 InputStreamReader isr = new InputStreamReader(in);//将字节流输入转换成字符输入流 5 BufferedReader br = new BufferedReader(isr);//对字符流对象进行包装 6 FileOutputStream out = new FileOutputStream("des1.txt"); 7 //将字节流转换为字符输出流 8 OutputStreamWriter osw = new OutputStreamWriter(out); 9 //对字符输出流对象进行包装 10 BufferedWriter bw = new BufferedWriter(osw); 11 String line; 12 while ((line=br.readLine())!=null){ //判断是否读到文件末尾 13 bw.write(line); //输出读取到文件 14 } 15 br.close(); 16 bw.close(); 17 } 18 }
三、其他IO流
1、ObjectOutputStream、ObjectInputStream
序列化:把对象按照流一样的方式传输或者存储。(ObjectOutputStream).
当对象进行序列化时,必须保证该对象实现Serializable接口,否则程序会出现NotSerializableException异常。
反序列号:把网络中的流数据或者文件中的流数据(二进制数据)还原成对象。(ObjectInputStream).
1 public class Example13 { 2 public static void main(String[] args) throws Exception{ 3 //序列化对象 4 Person person = new Person("p1","zhangsan",20); 5 //创建文件输出流对象,将数据写入objectStream.txt 6 FileOutputStream fos = new FileOutputStream("objectStream.txt"); 7 //创建对象输出流对象,用于处理输出流对象写入的数据 8 ObjectOutputStream oos = new ObjectOutputStream(fos); 9 //将Person对象输出到输出流中 10 oos.writeObject(person); 11 oos.close(); 12 13 //反序列化对象 14 FileInputStream fis = new FileInputStream("object.txt"); 15 //创建文件输入流对象,用于读取指定文件的数据 16 ObjectInputStream ois = new ObjectInputStream(fis); 17 //创建对象输入流,并且从指定的输入流中过读取数据 18 Object p = ois.readObject(); 19 System.out.println(p); 20 ois.close(); 21 } 22 } 23 class Person implements Serializable{ 24 private String id; 25 private String name; 26 private int age; 27 public Person(String id, String name, int age) { 28 super(); 29 this.id = id; 30 this.name = name; 31 this.age = age; 32 } 33 public String getId() { 34 return id; 35 } 36 public String getName() { 37 return name; 38 } 39 public int getAge() { 40 return age; 41 } 42 }
2、DataInputStream,DataOutputStream
有时候并不需要存储整个对象的信息,而只需要存储对象的成员数据,这些成员数据的类型又都是基本数据类型,可使用数据操作流:DataInputStream,DataOutputStream 。
1 public class Example15 { 2 public static void main(String[] args) throws Exception{ 3 BufferedOutputStream bos = new BufferedOutputStream( 4 new FileOutputStream("/Users/Shared/ioexample/dataStream.txt")); 5 DataOutputStream dos = new DataOutputStream(bos); 6 dos.writeByte(12); //写一个字节 7 dos.writeChar(\'1\'); //写一个字符 8 dos.writeBoolean(true); //写一个布尔值 9 dos.writeUTF("同学,你好"); //写一个转换成UTF-8的字符串 10 dos.close(); //关闭流 11 BufferedInputStream bis= new BufferedInputStream( 12 new FileInputStream("/Users/Shared/ioexample/dataStream.txt")); 13 DataInputStream dis = new DataInputStream(bis); 14 System.out.println(dis.readByte()); //读取一个字节 15 System.out.println(dis.readChar()); //读取一个字符 16 System.out.println(dis.readBoolean()); //读取一个布尔值 17 System.out.println(dis.readUTF()); //读一个转换成UTF-8编码的字符串 18 dis.close (); //关闭流 19 } 20 }
只有读取数据的顺序与写数据的顺序保持一致,才能保证最终数据的正常性。
3、打印流PrintStream
1 public class Example16 { 2 public static void main(String[] args) throws Exception{ 3 PrintStream ps = new PrintStream( 4 new FileOutputStream("printStream.txt",true)); 5 Student stu = new Student(); 6 ps.print("这是一个数字"); 7 ps.println(19); 8 ps.println(stu); 9 } 10 } 11 class Student { 12 @Override 13 public String toString() { 14 return "我是一个学生"; 15 } 16 }
4、标准输入输出流(in、out、err)
1 public class Example17 { 2 public static void main(String[] args) throws Exception{ 3 StringBuffer sb = new StringBuffer(); 4 int ch; 5 //while循环用于读取键盘输入的数据 6 while ((ch=System.in.read())!=-1){ //判断是否读取到数据的末尾 7 //对输入的字符进行判断,如果是回车"\\r"或者换行"\\n",则跳出循环 8 if(ch ==\'\\r\' || ch==\'\\n\'){ 9 break; 10 } 11 sb.append((char)ch); //将读取到的数据添加到sb中 12 } 13 System.out.println (sb); //打印键盘输入的数据 14 } 15 }
重定向流常用的静态方法
|
|
方法声明
|
功能描述
|
void setIn(InputStream in)
|
对标准输入流重定向
|
void setOut(PrintStream out)
|
对标准输出流重定向
|
void setErr(PrintStream out)
|
对标准错误输出流重定向
|
5、管道流(PipedInputStream、PipedOutputStream)
多线程之间可以通过此管道流实现数据的传输。
1 public class Example19 { 2 public static void main(String[] args) throws Exception{ 3 final PipedInputStream pis = new PipedInputStream();//创建PipedInputStream对象 4 final PipedOutputStream pos = new PipedOutputStream(); 5 //PipedInputStream和PipedOutputStream建立连接,也可写成pos.connect(pis) 6 pis.connect(pos); 7 new Thread(new Runnable(){ //创立线程 8 public void run(){ 9 //将从键盘读取的数据写入管道流中 10 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 11 //将从键盘读取的数据写入管道流中 12 PrintStream ps = new PrintStream(pos); 13 while (true){ 14 try{ 15 System.out.println(br.readLine()); 16 Thread.sleep(1000); 17 }catch (Exception e){ 18 e.printStackTrace(); 19 } 20 } 21 } 22 },"发送数据的线程").start(); 23 new Thread(new以上是关于Java入门——IO(输入与输出)的主要内容,如果未能解决你的问题,请参考以下文章