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 }
View Code
  文件拷贝:
 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 }
View Code
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 }
View Code
二、字符流
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 }
View Code

  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 }
View Code
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 }
View Code

三、其他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 }
View Code
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 }
View Code
  只有读取数据的顺序与写数据的顺序保持一致,才能保证最终数据的正常性。
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 }
View Code
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 }
View Code
 
重定向流常用的静态方法
方法声明
功能描述
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(输入与输出)的主要内容,如果未能解决你的问题,请参考以下文章

漫谈Java IO之普通IO流与BIO服务器

Java语言基础13—IO

Java语言基础13—IO

3小时Scala入门

片段(Java) | 机试题+算法思路+考点+代码解析 2023

JAVA入门到精通-第45讲-IO编程