Java I/O笔记 (续)

1.    FileInputStreamFileOutputStream

a)         FileInputStreamFileOutputStream类分别用来创建磁盘文件的输入流和输出流对象,通过它们的构造函数来指定文件路径和文件名。

b)         创建FileInputStream实例对象时,指定的文件应当是存在和可读的。创建FileOutputStream实例对象时,如果指定的文件已经存在,这个文件中的原来内容将被覆盖清除。

c)         对同一个磁盘文件创建FileInputStream对象的两种形式:

                         i.              FileInputStream inOne = new FileInputStream(“hello.txt”);

                       ii.              File f = new File(“hello.txt”);

FileInputStream inTwo = new FileInputStream(f);

d)         创建FileOutputStream实例对象时,可以指定还不存在的文件名,不能指定一个已经被其他程序打开的文件。

e)         思考:要将A文件的内容写入B文件,在程序代码中,是用输出流对象,还是用输入流对象来连接A文件并完成对A文件的操作呢?

输入输出是对程序本身而言的。所以要使用输入流对象连接A文件。

f)          变成举例:用FileOutputStream类向文件中写入一个字符串,然后用FileInpuStream读出写入的内容。

                         i.              FileStream

package com.file;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

 

public class FileStream {

    public static void main(String[] args) throws IOException {

       File file = new File("hello.txt");

      

       FileOutputStream out = new FileOutputStream(file);

       String str = new String("hello world!");

           out.write(str.getBytes());//写入文件中,内部调用flush

       out.flush();

       out.close();

      

       FileInputStream in = new FileInputStream(file);

       String receiveStr = "";

    /*  int b = in.read();

       while(b != -1) {

           receiveStr += (char) b;

           b = in.read();

       }*/

       byte[] buf = new byte[1024];

       int len = in.read(buf);

       receiveStr = new String(buf, 0, len);

       in.close();

       System.out.println(receiveStr);

    }

}

2.    ReaderWriter

a)         ReaderWriter是所有字符流类的抽象基类,用于简化对字符串的输入输出编程,即用于读写文本数据。

b)         二进制文件和文本文件的区别:

                         i.              本质上文件系统中的文件都是二进制文件。

                       ii.              文本文件是二进制文件的一种特例。

                      iii.              如果一个文件只用来存储字符,没有字符以外的数据,称这个文件为文本文件。

c)         编程举例:用FileWriter类向文件中写入一个字符串,然后用FileReader读出写入的内容。

                         i.              ReaderAndWriter类:

    package com.file;

 

import java.io.FileReader;

import java.io.FileWriter;

 

public class ReaderAndWriter {

    public static void main(String[] args) throws Exception {

       FileWriter fw = new FileWriter("hello2.txt");

       fw.write("hello world!");   //内部不会调用flush

       fw.flush();

       fw.close();

      

      

       FileReader fr = new FileReader("hello2.txt");

       char[] cbuf = new char[1024];

       int len = fr.read(cbuf);

       System.out.println(new String(cbuf, 0, len));

       fr.close();

      

    }

}

   

3.    PipedInptStreamPipedOutputStream

a)         PipedInputStream类与PipedOutputStream用于在应用程序中创建管道通信。完成线程之间的通信。

b)         PipedInputStreamPipedOutputStream类的变成实例。

                         i.              Dispatcher类:

 package com.pipe;

 

import java.io.IOException;

import java.io.PipedOutputStream;

 

public class Dispatcher extends Thread {

    private PipedOutputStream out = new PipedOutputStream();

   

    public PipedOutputStream getOutputStream() {

       return out;

    }

 

    @Override

    public void run() {

       String message = new String("hello world!");

       try {

           out.write(message.getBytes());  //发送消息

           out.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

    }

}

       Catcher类:

       package com.pipe;

 

import java.io.IOException;

import java.io.PipedInputStream;

 

public class Catcher extends Thread {

    private PipedInputStream in = new PipedInputStream();

   

    public PipedInputStream getInputStream() {

       return in;

    }

   

    @Override

    public void run() {

       byte[] buf = new byte[1024];

       int len;

       try {

           len = in.read(buf);

           String receieMsg = new String(buf, 0, len);   //接收消息

           System.out.println("接收到的字符串是:" + receieMsg);

           in.close();

       } catch (IOException e) {

           e.printStackTrace();

       }

    }

   

}

PipedStreamTest类:

package com.pipe;

 

import java.io.IOException;

import java.io.PipedInputStream;

import java.io.PipedOutputStream;

 

public class PipedStreamTest {

  public static void main(String[] args) throws IOException {

     Dispatcher dis = new Dispatcher();

     Catcher cat = new Catcher();

     PipedOutputStream out = dis.getOutputStream();

     PipedInputStream in = cat.getInputStream();

     out.connect(in);

     dis.start();

     cat.start();

    

  }

}

c)         使用管道流类,可以实现各个程序模块之间的松耦合通信。(模块具有强内聚弱耦合的特点)

d)         PipedWriterPipedReader

4.    ByteArrayInputStreamByteArrayOutputStream

a)         ByteArrayInputStreamByteArrayOutputStream,用于一IO流的方式来完成对字节数组内容的读写,来支持类似内存虚拟机文件或者内存映像文件的功能。

b)         ByteArrayInputStream的两个构造函数:

                         i.              ByteArrayInputStream(byte[] buf)

                       ii.              ByteArrayInputStream(byte[] buf, int offset, int length)

                      iii.              该流会从内存从中读取数据

c)         ByteArrayOutputStream的两个构造函数:

                         i.              ByteArrayOutputStream()

                       ii.              ByteArrayOutputStream(int)

                      iii.              流会数据会被写入缓存中。

d)         编程举例:编写一个把输入流中的所有英文字母变成大写字母,然后将结果写入到一个输出流对象。用这个函数来将一个字符串中的所有字符转换成大写。

                         i.              ByteArrayTest类:

 package com.bytes;

 

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

 

public class ByteArrayTest {

    public static void main(String[] args) throws IOException {

       String str = "abcdefghinklmnopqrstuvwxyz";

       ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());

       ByteArrayOutputStream bos = new ByteArrayOutputStream();

       transForm(bis, bos);

       System.out.println(new String(bos.toByteArray()));

    }

   

    public static void transForm(InputStream is, OutputStream os) throws IOException {

       int b = 0;

       while((b = is.read()) != -1) {

           int result = Character.toUpperCase((char) b);

           os.write(result);

       }

       os.close();

       is.close();

    }

}

e)   StringReader类和StringWriter类来以字符IO流的方式处理字符串。

5.    重视IO程序代码的复用

a)         System.in连接到键盘,是InputStream类型的实例对象。System.out连接到显示器,是PrintStream类的实例对象。

b)         不管各种底层物理设备用什么方式实现数据的终止点,InputStreamread方法总是返回-1来表示输入流的结束。

c)         Windows下,按下Ctrl+Z组合键可以产生键盘输入流的结束标记,在Linux下,则是按下Ctrl+D组合键来产生键盘输入流的结束标记。

d)         编程举例:借助上一页编写的函数,将键盘上输入的内容转变成大写字母后打印在屏幕上。

                         i.              加入此段代码:transForm(System.in, System.out);

e)         建议:要编程从键盘上连续读取一大段数据时,应尽量将读取数据的过程放在函数中完成。使用-1来作为键盘输入的结束点。在该函数中编写的程序代码不应直接使用System.in读取数据,而是用一个InputStream类型的形式参数对象来读取数据,然后将System.in作为实参传递给InputStream类型的形式参数来调用该函数。

6.    字符编码

a)         计算机里只有数字,计算机软件里的一切都是用数字表示的,屏幕上显示的一个个字符也不例外。

b)         字符a对应的数字是97,字符b对应的数字是98等,这中字符与数字对应的编码规则被称为ASCII(美国标准信息交换码)。ASCII的最高bit位都为0,即这些数字都在0127之间。

c)         中国大陆将每一个中文字符都用两个字节的数字来表示,中文字符的每个字节的最高位bit窦唯1,中国大陆为每个中文字符制定的编码规则成为GB2312(国标码)。

d)         GB2312的基础上,对更多的中文字符(包括繁体)进行了编码,新的编码规则成为GBK

e)         在中国大陆使用的计算机系统上,GBKGB2312就被称为该系统的本地字符集。

f)          “中国”的“中”字,在中国大陆的编码是十六进制ideD6D0,而在中国台湾的编码是十六进制的A4A4,台湾地区对中文字符集的编码规则称为BIG

g)         在一个国家的本地化系统中出现的一个字符,通过电子邮件传送到另外一个国家的本地化系统中,看到的就不是那个原始字符了,而是另外那个国家的一个字符或乱码。

7.    Unicode编码

a)         ISO(国际标准化组织)将全世界所有的符号进行了统一编码,称之为Unicode编码。

b)         “中”这个符号,在全世界的任何角落始终对应的都是同一个十六进制的数字4e2d

c)         如果所有的计算机系统都是用Unicode编码,在中国大陆的本地化系统中显示的“中”这个符号,发送到伊拉克的本地化系统中,显示的仍然是“中”这个符号。

d)         Unicode编码的字符都占用两个字节的大小,对于ASCII码所表示的字符,只是简单地在ASCII码原来占用一个字节的前面,增加一个所有bits0的字节。

e)         Unicode只占用两个字节,在全世界范围内所表示的字符个数不会超过216次方(65536),实际上,Unicode编码中还保留了两千多个数值没有用于字符编码。

f)          在相当长的一段时间内,本地化字符编码将于Unicode编码共存。

g)         Java中的字符使用的都是Unicode编码,Java在通过Unicode保证跨平台特性的前提下,也支持本地平台字符集。

8.    UTF-8编码

a)         ASCII码字符保持原样,仍然只占用一个字节,对于其他国家的字符,UTF-8使用两个或三个字节表示,使用UTF-8编码的文件,通常都要用EF BB BF作为文件开头的三个字节数据。

b)         UTF-8的优点:不会出现内容为0x00字节

便于应用程序检测数据在传输过程中是否发生了错误。

直接处理使用ASCII码的英文文档。

c)         UTF-8的缺点:有些字符需用三个字节。

9.    UTF-16编码

a)         是对Unicode的扩充,编码格式与Unicode一样。占用两个字节,扩充字符占用4个字节。

10. 过滤流与包装类

a)         包装类的概念与作用

                         i.              作用:简化各种不同类型数据写入到文件的步骤,使操作数据更加方便。

                       ii.              通过FileOutputStream对象将一个浮点小数写入到文件中(可用floatToIntBits(float value)方法)比较复杂。

                      iii.              假如有个DataOutputStream类提供了往各种输出流对象中写入各种类型数据(包括浮点小数)的方法。只需传递一个FileOutputStream输出流对象给DataOutputStream调用。

                      iv.                包装流类与节点流的关系图

 

 

 

b)         BufferedInputStreamBufferedOutputStream

                         i.              缓冲流为I/O流增加了内存缓冲区,增加缓冲区的目的:

1.         允许Java程序一次操作多个字节,提高程序性能。

2.         有了缓冲区,使得在流上之心skipmarkreset方法都成为可能。

 

                       ii.              BufferedInputSteamBufferedOutputStreamJava提供的两个缓冲区包装类,不管底层是否使用缓冲区,这两个类的实例对象都创建缓冲区。

                      iii.              BufferedReaderBufferedWriter

1.         BufferedRederreadLine可以一次读取一行文本。读到回车(‘/n’)或换行(‘/r’)为止。

2.         BufferedWriternewLine方法可以向字符流中写入不同操作系统下的换行符。

c)         DataInputStreamDataOutputStream

                         i.              由于DataOutputStreamwriteBytes(String s) writeChars(String s) 没有指定写入的字符串长度,所以DataInputStream没有readBytes()readCahrs()方法。

                       ii.              编程实例:分别使用DataOutputStream类的writeUTFwriteByteswriteChars方法,比较这几个方法的差异。程序中所使用的流栈如下图:

1.        

2.         关闭流栈的最上层的流对象(DataOutputStreamDataInputStream),将会自动关闭流栈中的所有底层流对象。

d)         PrintStream

                         i.              PrintStream类提供了一系列的printprintln方法,可以将基本数据类型的数据格式化成字符串输出。

                       ii.              格式化输出是:将数据转换成ASCII码形式。(例如97被格式化的实际字节数据为0x390x37

                      iii.              PrintStream对应的PrintWriter类,即使遇到了文本换行标识符(/n),PrintWriter类也不自动清空缓冲区。其生成的换行标识符是根据系统默认的标识符而确定的。

e)         ObjectInputStreamObjectOutputStream

                         i.              ObjectInputStreamObjectOutputStream这两个包装类用于从底层输入流中读取对象类型的数据和将对象类型的数据写入到底层输入流。

                       ii.              ObjectInputStreamObjectOutputStream类所读写的对象必须实现Serializable接口。对象中的transientstatic类型的成员变量不会被读取和写入。

                      iii.              一个可以被序列化的MyClass类的定义:

1.         public class MyClass implements Serializable {

            public transient Thread t;

                   private String customerID;

                   private int total;

2.         }

                      iv.              编程举例:创建一个可序列化的学生对象,并用ObjectOutputStream类把它存储到一个文件(object.txt)中,然后再用ObjectInputStream类把存储的数据读取到学生对象中,即恢复保存的学生对象。

import java.io.Serializable;

 

public class Student implements Serializable {

  private int id;

  private int age;

  private String name;

  private String department;

 

  public Student(int id, int age, String name, String department) {

     this.id = id;

     this.age = age;

     this.name = name;

     this.department = department;

  }

 

  public String toString() {

     return "id=" + id + " ,age=" + age + " ,name=" + name + " ,department=" + department;

  }

 

}

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

 

public class ObjectStreamTest {

  public static void main(String[] args) throws Exception {

    

     Student s1 = new Student(1, 18, "xiaoming", "nature");

     Student s2 = new Student(2, 20, "xiaogang", "nature");

    

     FileOutputStream fos = new FileOutputStream("object.txt");

     ObjectOutputStream oos = new ObjectOutputStream(fos);

     oos.writeObject(s1);

     oos.writeObject(s2);

     oos.close();

    

     FileInputStream fis = new FileInputStream("object.txt");

     ObjectInputStream ois = new ObjectInputStream(fis);

     Student fromS1 = (Student) ois.readObject();

     Student fromS2 = (Student) ois.readObject();

     ois.close();

     System.out.println(fromS1);

     System.out.println(fromS2);

    

  }

}

f)          字节流与字符流的转换

                         i.              能不能找到一种简单的方式来读取键盘上输入的一行字符,如何找?

1.         在帮助文档中找带有readLine的方法的类。

2.         可以找到BufferedReader等类,使用BufferedReader类读取键盘上的一行字符需用转换流InputStreamReader

                       ii.              InputStreamReaderOutputStreamWriter,是用于将字节流转换成字符流来读写的两个类。InputStreamReader可以将一个字节流中的字节解码成字符后读取,OutputStreamWriter将字符编码成字节后写入到一个字节流中。

                      iii.              为了避免频繁地在字符与字节间进行转换,最好不要直接使用InputStreamReaderOutputStreamWriter类来读写数据,应尽量使用BufferedWriter类包装OutputStreamWriter类,用BufferedReader类包装InputStreamReader类。

11. Java程序与其它进程的数据通信

a)         Java程序中可以用Process类的实例对象来表示子进程,子进程的标准输入和输出不再连接到键盘和显示器,而是以管道流的形式连接到父进程的一个输出流和输入流对象上。

b)         调用Process类的getOutputStreamgetInputStream方法可以获得连接到子进程的输出流和输入流对象。

c)         编程实例:在InOutTest类中启动Java.exe命令执行另外一个MyTest 类,InOutTestMyTest通过进程间的管道相互传递数据。

 

 

d)         验证管道缓冲区满后,将发生下面的哪种情况:

                         i.              新的数据写入时,将最前面写入的数据挤出去,从而发生数据丢失。

                       ii.              PipedInputStream相连接的PipedOutputStream无法再写入新的数据,PipedOutputStream.write方法处于阻塞状态,并抛出异常。

                      iii.              调用Process类的destory方法结束子进程的运行。

e)         提高程序的运行效率

                         i.              for(int i=0; i<str.length(); i++) {

1.         ……

                       ii.              }

                      iii.              改写成:

                      iv.              int len = str.length();

                       v.              for(int i=0; i<len; i++) {

1.         ……

                      vi.              }                           就是多想几步。

12. 总结

a)         java.io包中定义了多个流类型(类或抽象类)来实现输入/输出功能:可以从不同的角度对其进行分类:

                         i.              按数据流的方向不同可以分为输入流和输出流。

                       ii.              按处理数据单位的不同可以分为字节流和字符流。

                      iii.              按照功能的不同可以分为节点流和处理流。

b)         c)        

d)        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值