Day13:IO流(补充内容:特殊流对象)

Properties
    特点:
    1,Hashtable的子类,map集合中的方法都可以用。
    2,该集合没有泛型。键值都是字符串。
    3,它是一个可以持久化的属性集。键值可以存储到集合中,也可以存储到持久化的设备上。
        键值的来源也可以是持久化的设备。
    4,有和流技术相结合的方法。load(InputStream)  load(Reader)  store(OutputStream,commonts); stro(Writer,comments);    
        
-------------------------------------------

IO流的规律总结:解决的问题,就是开发中具体要使用哪个流对象的问题。

1,明确数据源,数据汇(数据目的)
    其实就是在明确要使用的IO体系。InputStream OutputStream   Reader Writer
    需求中操作的是源:意味着是读。
    InputStream Reader
    
    需求中操作的目的:意味着是写。
    OutputStream  Writer 
    
2,明确操作的数据是否是纯文本数据?
    是,字符流。
    否,字节流。
    
    是并且是源。Reader
    
    是并且也是目的,Writer。
    
    
通前两个明确,明确了具体要使用的体系。

接下来应该明确具体的体系中要使用哪个对象。

3,明确要操作的具体设备。每个设备都有对应的流对象。
    源设备:
        硬盘,能操作File的流对象都是。File开头。
        键盘,System.in;
        内存,数组。
        网络,socket流。
        
    目的设备:
        硬盘,能操作File的流对象都是。File开头。
        显示器,System.out
        内存,数组。
        网络。socket流。

到第三步明确就可以找到具体的流对象了。

4,需要额外功能吗?
    需要高效吗?缓冲区,Buffered开头。
    需要编码转换吗?转换流。
    


需求1:通过键盘录入数据,将数据保存到一个文件中。
    明确一:有源吗?有,有目的吗?有。
    源:InputStream Reader
    目的:OutputStream  Writer
    
    明确二:是纯文本数据吗?是。
    源:Reader
    目的:Writer。
    
    明确三:具体设备。
    源设备:System.in;
    目的设备:硬盘。
    
    InputStream is = System.in;
    FileWriter fw = new FileWriter("a.txt");
    
    //将读取的字节存储到数组 read(byte[])
    //将字节数组转成字符串。
    //通过fw.write(string)写入到文件中。
    
    //但是麻烦。因为明确源是Reader,需要将字节流转成字符流,这样操作文字就便捷了。
    
    明确四:需要功能吗?
    需要,转换。字节--->字符。InputStreamReader
    
    InputStreamReader isr = new InputStreamReader(System.in);
    FileWriter fw = new FileWriter("a.txt");
    //一次读取一个字符。
    //将读到的字符写入。
    //当也可以定义字符数组缓冲区。
    
    
    需要其他功能 吗?
    需要,高效。Buffered
    
    BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
    Bufferedwriter bufw = new BufferedWriter(new FileWriter("a.txt"));    

    //line = readLine();
    //bufw.write(string); bufw.flush();

    


需求2:读取文本文件中的数据,将其打印到控制台上。
    明确一:有源吗?有,有目的吗?有。
    源:InputStream Reader
    目的:OutputStream  Writer
    
    明确二:是纯文本。
    源:Reader
    目的:Writer
    
    明确三:明确设备。
    源设备:
    硬盘:FileXXX
    目的设备:
    显示器:System.out
    
    
    
    FileReader fr = new FileReader("a.txt");
    OutputStream(PrintStream) out = System.out;
    
    //fr读取数据到数组中。
    //使用PrintStream直接调用println方法就可以打印了。如果使用OutputStream可以调用writer方法就可以将数据写入到显示器上。
    
    //麻烦。
    
    //因为源都是字符数据。可以通过字符流操作,将字符转成字节在给显示器。
    需要额外功能吗?
    需要转换 字符-->字节。
    FileReader fr = new FileReader("a.txt");
    OutputStreamWriter osw = new OutputStreamWriter(System.out);
    
    
    //还需要额外功能吗?
    需要高效。
    BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
    BufferedWriter bufw = new BufferdWriter(new OutputStreamWriter(System.out));
    
    //读取一行数据。
    //写入一行数据。
    
自己动手将下列需求按照流的规律写出来。
需求3:读取键盘录入的数据,转成大写打印到控制台上。录入over结束。

需求4:读取文本文件,将数据按照U8编码保存到文件中。

  

IO包中的其他功能流对象。
功能流对象
特点.解决的问题,特有方法。

打印流--输出流
PrintStream (字节流) PrintWriter(字符流)
特点:打印。不抛异常。
打印的目的:File对象,字符串路径,字节输出流。

解决问题:方便地打印各种数据值表示形式。
        它的打印方法可以保证数值的表现形式不变。写的是什么样子,目的就是什么样子。

PrintWriter:一样具备打印功能。
    目的:File对象,字符串路径,字节输出流,字符输出流。
    
---
序列流:
特点:流对象的有序的排列。
解决问题:将多个输入流合并成一个输入流。将多个源合并成一个源。对于多个源的操作会变的简单。
功能:特殊之处在构造函数上。一初始化就合并了多个流进来。

使用场景之一:对多个文件进行数据的合并。多个源对应一个目的。

自选题:对一个文件进行切割(一个源对应多个目的),切成碎片,在将碎片进行合并成原来的文件。

-------
用于操作对象的流对象。对象的序列化。
ObjectInputStream,ObjectOutputStream
特点:用于操作对象。
解决问题:可以将对象进行序列化和反序列化。注意:对象序列化一定要实现Serializable接口。为了给类定义一个serialVersionUID。
功能:ObjectInputStream readObject()   ObjectOutputStream writeObject()
关键字:瞬态:transient

------
RandomAccessFile:
特点:只能操作文件。
        既能读,又能写。
        维护了一个byte数组。内部定义了字节流的读取和写入。
        通过对指针的操作可以实现对文件的任意位置的读取和写入。

功能:getFilePointer seek用于操作文件指针的方法。


------
管道流。
特点:读取管道和写入管道可以连接。
        需要使用多线程技术。单线程容易死锁。

功能:connect()

------------
操作基本数据值的对象。
DataInputStream DataOutputStream
用于操作基本数据类型值。
write基本类型  read基本类型。


----------
操作数组的流对象。
特点:不需要关闭。不抛出IO异常。
用IO的读写思想操作数组。



练习:

按照字节数截取一个字符串。"abc你好"如果截取到半个中文,舍弃。比如 截取4字节,abc。截取5个字节abc你。
定义功能实现。

字符串-->字节数组。编码
字节数组-->字符串。解码。
     
友情提示:GB2312编码的一个中文是两个字节,而且两个字节的最高位都是1.也就是说是一个负数。
         


============================================================

IO流的体系:


字节流
OutputStream
    |--FileOutputStream:★★★★★
    |--FilterOutputStream:no
        |--BufferedOutputStream:★★★★★
        |--DataOutputStream:
        |--PrintStream:
    |--ObjectOutputStream:
    |--PipedOutputStream:
    |--ByteArrayOutputStream:
    
    

InputStream
    |--FileInputStream:★★★★★
    |--FilterInputSteam:no
        |--BufferedInputStream:★★★★★
        |--DataInputStream:
    |--ObjectInputStream:
    |--PipedInputStream:
    |--ByteArrayInputStream:
    |--SequenceInputStream:
            



字符流

Reader
    |--BufferedReader:★★★★★
        |--LineNumberReader:
    |--InputStreamReader:★★★★★
        |--FileReader:★★★★★
    |--CharArrayReader:
    |--StringReader:
    


Writer
    |--BufferedWriter:★★★★★
    |--OutputStreamWriter:★★★★★
        |--FileWriter:★★★★★
    |--PrintWriter:★★★★★
    |--CharArrayWriter:
    |--StringWriter:


RandomAccessFile:

File:★★★★

    /*
      *文件分割器
      */
    if(!srcFile.exists()){
          throw new RuntimeException(srcFile.getAbsolutePath()+",源文件不存在");
        }
        
        if(!destDir.exists()){
            destDir.mkdirs();
        }
        
        //1,读取源文件。
        FileInputStream fis = new FileInputStream(srcFile);
        
        //2,创建目的引用。
        FileOutputStream fos = null;
        
        //3,创建一个缓冲区。1M
        byte[] buf = new byte[1024*1024];//1M
        int count = 0;
        int len = 0;
        //4,往缓冲区存储数据。
        while((len=fis.read(buf))!=-1){
        
            //5,创建输出流。并明确要写入的文件对象。
            
            File partFile = new File(destDir,(++count)+".part");
            fos = new FileOutputStream(partFile);
            fos.write(buf,0,len);
            fos.close();
        }
        //应该在产生碎片文件时,需要产生一个配置文件。记录碎片的个数和源文件的名字。
        //partcount = 5;  filename = 1.mp3;
        
        //配置文件中存储的键值信息。使用Properties集合。
        Properties prop = new Properties();
        
        prop.setProperty("partcount", Integer.toString(count));
        prop.setProperty("filename", srcFile.getName());
        File configFile = new File(destDir,(++count)+".properties");
        fos = new FileOutputStream(configFile);
        prop.store(fos, "save part file info");
        
        fos.close();
        fis.close();
public class PipedStreamDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {

        //创建管道对象。
        PipedInputStream pis = new PipedInputStream();
        PipedOutputStream pos = new PipedOutputStream();
        //将两个流连接上。
        pis.connect(pos);
        
        new Thread(new Input(pis)).start();
        new Thread(new Output(pos)).start();
        
        
    }

}


//定义输入任务。
class Input implements Runnable{

    private PipedInputStream pis;
    
    public Input(PipedInputStream pis) {
        super();
        this.pis = pis;
    }

    @Override
    public void run() {
        
        byte[] buf = new byte[1024];
        int len;
        try {
            len = pis.read(buf);
            String str = new String(buf,0,len);
            System.out.println(str);
            
            pis.close();
        } catch (IOException e) {
            
            e.printStackTrace();
        }
        
    }
    
    
}
//定义输出任务。
class Output implements Runnable{

    private PipedOutputStream pos;
    
    public Output(PipedOutputStream pos) {
        super();
        this.pos = pos;
    }

    @Override
    public void run() {
        //通过write写方法完成。
        try {
            pos.write("hi,管道来了!".getBytes());
            
            pos.close();
        } catch (IOException e) {
            
            e.printStackTrace();
        }
    }
}
public class RandomAccessFileDemo {

    /**
     * @param args
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {  
        /*
         * RandomAccessFile:
         * 特点:
         * 1,只能操作文件。
         * 2,既能读,又能写。
         * 3,维护了一个byte数组。内部定义了字节流的读取和写入。
         * 4,通过对指针的操作可以实现对文件的任意位置的读取和写入。
         */    
        writeFile();
        readFile();
    }

    public static void readFile() throws IOException {
        
     RandomAccessFile raf = new RandomAccessFile("tempfile\random.txt", "r");
        
        //随机读取,只要通过设置指针的位置即可。
        raf.seek(8*1);
        
        byte[] buf = new byte[4];
        raf.read(buf);
        String name = new String(buf);
        
        int age = raf.readInt();
        
        System.out.println(name+":"+age);
        
        raf.close();    
    }

    public static void writeFile() throws IOException {
        
        //1,创建一个随机访问文件的对象。文件不存在,则创建,存在,则不创建不覆盖。
    RandomAccessFile raf = new RandomAccessFile("tempfile\random.txt", "rw");
        
        //2,写入姓名和年龄。
        raf.write("张三".getBytes());
        raf.writeInt(97);//保证整数的字节原样性。
        raf.write("李四".getBytes());
        raf.writeInt(99);//保证整数的字节原样性。
        
        //3,随机写入。
        raf.seek(8);//设置指针的位置。
        raf.write("王武".getBytes());
        raf.writeInt(100);
        System.out.println(raf.getFilePointer());
        
        raf.close();    
    }
}
原文地址:https://www.cnblogs.com/vijay/p/3524699.html