Crazy Java study notes (55) ------------ byte stream and character stream

Crazy Java study notes (55) ------------ byte stream and character stream

byte stream and character stream

There are two main types of file content manipulation in the java.io package: byte stream and character stream, both of which are divided into input and output operations. The output data in the byte stream is mainly completed by the OutputStream , the input is the InputStream , the output in the character stream is mainly completed by the Writer class, and the input stream is mainly completed by the Reader class. (these four are abstract classes)

 

The usage of processing stream:

 
According to whether the flow is directly connected to a specific place (such as disk, memory, device, etc.), it is divided into two categories: node flow and processing flow .
  

 Node Stream : Data can be read and written from or to a specific place (node). For example, FileReader 
  
 processes streams : it is the connection and encapsulation of an existing stream, and data read and write is realized through the function call of the encapsulated stream.


 Such as BufferedReader. Constructors that handle streams always take an additional stream object as a parameter. A stream object is wrapped multiple times by other streams, which is called stream chaining. 
  
  

Common Node Streams 


Parent class InputStream OutputStream Reader Writer 
file *FileInputStream FileOutputStrean FileReader FileWriter File processing node stream 
array *ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter 
processing node stream (corresponding no longer a file, but an array in memory) 
string* No No StringReader StringWriter Node stream
pipeline  for string processing  *PipedInputStream PipedOutputStream PipedReader PipedWriter Node stream processing stream for pipeline processing
 
  commonly used processing stream (close the node stream inside the processing stream) 


Parent class InputStream OutputStream Reader Writer 
Buffered Stream *BufferedImputStrean BufferedOutputStream BufferedReader BufferedWriter ---- needs the parent class as a parameter to construct, increase the buffering function, avoid frequent reading and writing of the hard disk, and can initialize the size of the buffered data. Because of the buffering function, it is written When you need to use the flush method, you need to use the flush method.

 Conversion stream *InputStreamReader OutputStreamWriter- takes inputStream or OutputStream as a parameter, realizes conversion from byte stream to character stream Data stream *DataInputStream DataOutputStream - provides basic data types written to files, or read out, why have this stream Woolen cloth?

Looking at this analysis, if there is no such stream, there is a long, which itself only occupies 8 bytes. If I want to write to a file, I need to convert it into a string, and then convert it into a character array, it will take up a lot of space , but it is very convenient to have this kind of stream, and it is done by directly writing these 8 bytes to the file. . Does it save memory space and make the program more convenient and simple to write? Writing is very simple, but pay attention when reading. According to the type of data read, the pointer will move down, so the order of writing must be the same as the order of reading to complete your correct needs.

 

Therefore, the typical idea when we use processing streams is: use processing streams to wrap byte streams, and programs perform input/output functions by processing streams, allowing byte streams to interact with underlying I/O devices and files.

 

Input and output stream system:

 

Java's input and output streams provide nearly 40 classes: it seems to be irregular, but we can divide them by function: as shown below:

 

 

Generally speaking, byte streams are more powerful than character streams, because all data in a computer is binary, you know!

But I still like the character flow, straight to the point.

 

 

transform stream

 

Two transform streams:

1. Convert bytes to character stream

InputStreamReader: Convert byte input stream to character input stream, OutPutStreamWriter: Convert byte output stream to character output stream

    2. From character stream to byte stream: You can get the char[] array from the character stream, convert it to String, and then call the String API function getBytes() to get the byte[], and then you can use ByteArrayInputStream and ByteArrayOutputStream to achieve Conversion of byte streams.


package com.haixu.io;  
  
import java.io.BufferedReader;  
import java.io.InputStreamReader;  
  
public class KeyinTest {  
      
    public static void main(String[] args) {  
          
        try {  
            //Convert system.in object to Reader object  
            System.out.println("请输入:");  
            InputStreamReader reader = new InputStreamReader(System.in);  
            //将Reader对象转换成BufferedReader对象  
            BufferedReader br = new BufferedReader(reader);  
              
            String buffer = null;  
            //进行逐行的读取  
            while((buffer = br.readLine()) != null){  
                  
                //如果读取的内容为exit,则退出程序  
                if(buffer.equals("exit")){  
                    System.exit(1);  
                }  
                System.out.println("输入内容为:" + buffer);  
            }  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
finally{reader.close();br.close()}//不要忘记关闭流 我忘记了,后加入的!   

弄点高大尚的:

 

推回输入流

在输入输出流中,有两个特殊的流:  PushbackInputStream 和  PushbackReader

 

 

 

Pushback用于输入流允许字节被读取然后返回(即“推回”)到流。PushbackInputStream类实现了这个想法。它提供了一种机制来“窥视”在没有受到破坏的情况下输入流生成了什么。

PushbackInputStream有两个构造函数:
PushbackInputStream(InputStream inputStream)
PushbackInputStream(InputStream inputStream, int numBytes)
第一种形式创建了一个允许一个字节推回到输入流的流对象。第二种形式创建了一个具有numBytes长度缓冲区的推回缓冲流。它允许多个字节推回到输入流。除了具有与InputStream相同的方法,PushbackInputStream提供了unread( )方法,表示如下:
void unread(int ch)
void unread(byte buffer[ ])
void unread(byte buffer, int offset, int numChars)
第一种形式推回ch的低位字节,它将是随后调用read( )方法所返回的下一个字节。第二种形式返回buffer缓冲器中的字节。第三种形式推回buffer中从offset处开始的numChars个字节。如果在推回缓冲器为满时试图返回一个字节,IOException异常将被引发。Java 2 对PushbackInputStream作了一些小的修改:它实现skip( )方法。
实例:
package com.haixu.io;  
  
import java.io.FileReader;  
import java.io.PushbackReader;  
  
public class PushBackTest {  
    /** 
     * 推回输入流练习 
     *  
     * */  
    public static void main(String[] args) {  
        try {  
            /* 
             * 创建推回输入流的对象,并设定缓存的大小为:64字节 
             * */  
            PushbackReader pr = new PushbackReader(  
                    new FileReader("E://Java编程//Java06//src//com//haixu//io//PushbackTest.java") , 64);   
            char [] buf = new char[64];  
            //用于保存上次读取的字符串内容  
            String lastContent = "";  
            int hasRead = 0;  
  
            //循环读取文件内容  
            while((hasRead = pr.read(buf)) > 0 ){  
  
                String content = new String(buf , 0 , hasRead);  
                int targetIndex = 0 ;  
  
                //将上次读取的内容与本次读取的内容拼接起来  
                //查看是否包含目标字符串,如果包含目标字符串  
                if((targetIndex = (lastContent + content).indexOf("new PushbackReader"))>0){  
  
                    //将本次内容与上次内容一起推回缓冲区  
                    pr.unread((lastContent + content).toCharArray());  
                    int len = targetIndex >32 ? 32 : targetIndex;  
  
                    //指定读取指定长度的内容  
                    pr.read(buf , 0 , len);  
  
                    //打印输出  
                    System.out.println(new String(buf ,0 , len));  
                    System.exit(0);  
                }else{  
                    System.out.println(lastContent);  
                    //将本次内容设定上次读取的内容  
                    lastContent = content;  
                }  
            }  
  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
  
}<span style="color:#ff0000;">  
</span>  
重定向输入输出

Java的标准输入/输出分别通过System.in和System.out来代表,在默认的情况下分别代表键盘和显示器,当程序通过System.in来获得输入时,实际上是通过键盘获得输入。当程序通过System.out执行输出时,程序总是输出到屏幕。

在System类中提供了三个重定向标准输入/输出的方法

static void setErr(PrintStream err) 重定向“标准”错误输出流

static void setIn(InputStream in)    重定向“标准”输入流

static void setOut(PrintStream out)重定向“标准”输出流

package com.haixu.io;  
  
import java.io.FileOutputStream;  
import java.io.PrintStream;  
  
public class RedirectOut {  
  
    public static void main(String[] args) {  
        try {  
            /* 
             * 一次性创建PrintStream输出流 
             */  
            PrintStream ps = new PrintStream(new FileOutputStream("out.text"));  
              
            //将标准输入重定向到ps输入流中  
            System.setOut(ps);  
              
            //向标准输入一个字符串  
            System.out.println("普通字符串");  
            //向标准输出输出一个对象  
            System.out.println((new RedirectOut()));  
              
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
}  
package com.haixu.io;  
  
import java.io.FileInputStream;  
import java.util.Scanner;  
  
public class RedirectIN {  
  
    public static void main(String[] args) {  
        try {  
            //创建FileInputStreamd对象  
            FileInputStream fis = new FileInputStream("E://Java编程//Java06//src//com//haixu//io//RedirectIN.java");  
  
            //标准的输入重定向到fis输入流  
            System.setIn(fis);  
  
            //使用System.in创建Scanner对象,用于标准的输入  
            Scanner sc = new Scanner(System.in);  
            //回车  
            sc.useDelimiter("/n");  
            while(sc.hasNext()){  
                System.out.println("键盘输入的内容" + sc.next());  
            }  
        } catch (Exception e) {  
            // TODO: handle exception  
            e.printStackTrace();  
        }  
    }  
  
}  

RandomAccessFile

RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了。这些记录的大小不必相同;但是其大小和位置必须是可知的。但是该类仅限于操作文件。

RandomAccessFile不属于InputStream和OutputStream类系的。实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫不相干,甚至不使用InputStream和OutputStream类中已经存在的任何功能;它是一个完全独立的类,所有方法(绝大多数都只属于它自己)都是从零开始写的。这可能是因为RandomAccessFile能在文件里面前后移动,所以它的行为与其它的I/O类有些根本性的不同。总而言之,它是一个直接继承Object的,独立的类。

基本上,RandomAccessFile的工作方式是,把DataInputStream和DataOutputStream结合起来,再加上它自己的一些方法,比如定位用的getFilePointer( ),在文件里移动用的seek( ),以及判断文件大小的length( )、skipBytes()跳过多少字节数。此外,它的构造函数还要一个表示以只读方式("r"),还是以读写方式("rw")打开文件的参数 (和C的fopen( )一模一样)。它不支持只写文件。

只有RandomAccessFile才有seek搜寻方法,而这个方法也只适用于文件。BufferedInputStream有一个mark( )方法,你可以用它来设定标记(把结果保存在一个内部变量里),然后再调用reset( )返回这个位置,但是它的功能太弱了,而且也不怎么实用。

 

 

内存映射文件

内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。
fileChannel.map(FileChannel.MapMode mode, long position, long size)将此通道的文件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大;也就是说,它还可以映射一个大文件的某个小片断。


MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法,但新添了force()将缓冲区的内容强制刷新到存储设备中去、load()将存储设备中的数据加载到内存中、isLoaded()位置内存中的数据是否与存储设置上同步。这里只简单地演示了一下put()和get()方法,除此之外,你还可以使用asCharBuffer( )之类的方法得到相应基本类型数据的缓冲视图后,可以方便的读写基本类型数据。


/* 
 * 程序功能:演示了RandomAccessFile类的操作,同时实现了一个文件复制操作。 
 */  
package com.lwj.demo;  
  
import java.io.*;  
  
public class RandomAccessFileDemo {  
 public static void main(String[] args) throws Exception {  
  RandomAccessFile file = new RandomAccessFile("file", "rw");  
  // 以下向file文件中写数据  
  file.writeInt(20);// 占4个字节  
  file.writeDouble(8.236598);// 占8个字节  
  file.writeUTF("这是一个UTF字符串");// 这个长度写在当前文件指针的前两个字节处,可用readShort()读取  
  file.writeBoolean(true);// 占1个字节  
  file.writeShort(395);// 占2个字节  
  file.writeLong(2325451l);// 占8个字节  
  file.writeUTF("又是一个UTF字符串");  
  file.writeFloat(35.5f);// 占4个字节  
  file.writeChar('a');// 占2个字节  
  
  file.seek(0);// 把文件指针位置设置到文件起始处  
  
  // 以下从file文件中读数据,要注意文件指针的位置  
  System.out.println("——————从file文件指定位置读数据——————");  
  System.out.println(file.readInt());  
  System.out.println(file.readDouble());  
  System.out.println(file.readUTF());  
  
  file.skipBytes(3);// 将文件指针跳过3个字节,本例中即跳过了一个boolean值和short值。  
  System.out.println(file.readLong());  
  
  file.skipBytes(file.readShort()); // 跳过文件中“又是一个UTF字符串”所占字节,注意readShort()方法会移动文件指针,所以不用加2。  
  System.out.println(file.readFloat());  
    
  //以下演示文件复制操作  
  System.out.println("——————文件复制(从file到fileCopy)——————");  
  file.seek(0);  
  RandomAccessFile fileCopy=new RandomAccessFile("fileCopy","rw");  
  int len=(int)file.length();//取得文件长度(字节数)  
  byte[] b=new byte[len];  
  file.readFully(b);  
  fileCopy.write(b);  
  System.out.println("复制完成!");  
 }  
}  
/** 
 *  
 * @param skip 跳过多少过字节进行插入数据 
 * @param str 要插入的字符串 
 * @param fileName 文件路径 
 */  
public static void beiju(long skip, String str, String fileName){  
    try {  
        RandomAccessFile raf = new RandomAccessFile(fileName,"rw");  
        if(skip <  0 || skip > raf.length()){  
            System.out.println("Invalid number of skipped bytes");  
            return;  
        }  
        byte[] b = str.getBytes();  
        raf.setLength(raf.length() + b.length);  
        for(long i = raf.length() - 1; i > b.length + skip - 1; i--){  
            raf.seek(i - b.length);  
            byte temp = raf.readByte();  
            raf.seek(i);  
            raf.writeByte(temp);  
        }  
        raf.seek(skip);  
        raf.write(b);  
        raf.close();  
    } catch (Exception e) {  
        e.printStackTrace ();  
    }  
}  

Reprinted from: https://blog.csdn.net/u011225629/article/details/46236993



Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326682165&siteId=291194637