您的位置:首页 > 编程语言 > Java开发

[Thinking in Java] - No.10 Stream、File和IO(2):Stream和IO初探

2017-09-27 21:09 477 查看
IO中经常会使用到的概念是“流”。在IO中,有两种流,分别对应字符流和字节流。

字节流: Java中的字节流处理的最基本单位为单个字节。

字符流:Java中的字符流处理的最基本的单元是Unicode码元。

字节流通常用于处理二进制数据,实际上它可以处理任意类型的数据。但它不支持直接写入或读取Unicode码元,所以使用字节流处理中文常常会乱码。字符流通常处理文本数据,它支持写入及读取Unicode码元。

字符流在IO的时候会先把数据读写到缓冲区中,然后再写入文本。而字节流则是直接操纵文本。



如何体验出字符流使用缓存而字节流不使用缓存呢?我们看下面的例子

public static void main(String args []) throws IOException{
File file = new File("E:\\test001.txt");
File file1 = new File("E:\\test002.txt");

FileWriter fWriter = new FileWriter(file);
FileOutputStream fStream = new FileOutputStream(file1);
String str = "Hello World";
fWriter.write(str);
fStream.write(str.getBytes());
//fWriter.close();
//fStream.close();
}
在上面的例子中,我们注释掉了close()函数,所以两个流均没有关闭。运行程序我们发现。字符流对应的test001没有写入"Hello World",但是字节流对应的test002写入了。我们将程序中两个流均关闭,重新运行函数,两个文本均写入指定字符串。所以我们可以发现,字节流是直接操纵文本,字符流则是通过缓冲区操纵文本,同时在close()函数或者flush()执行的时候写入文本。

Java中的I/O类库按照字符流和字节流分为以下:



简单的归纳一下:

字符流:使用缓冲区读写-使用Reader/Writer进行IO

字节流:直接操作文本-使用InputStream/OutputStream进行IO

在字符流中,我们常用到:FileReader/FileWriter和BufferReader/BufferWriter

在字节流中,我们常使用:FileInputStream/FileOutputStream和BufferInputStream/BufferOutputStream

字符流:

FileReader/FileWriter使用:

File file = new File("E:\\class.txt");
FileReader fileReader = new FileReader(file);
char[] cbuf = new char [1000];
fileReader.read(cbuf);
for(char c:cbuf)
{
System.out.print(c);
}

FileWriter fWriter = new FileWriter(new File("E:\\test123.txt"),true);
fWriter.write("123456");
fWriter.write("nihaoa");
Reader和Writer的函数都很简单可以自行查看。这里注意两个函数:write()函数和append()函数。

write()函数和append()函数均是向文本中写入,两者本身没没有太大区别,网上普遍认为append是追加,write是复写,这是错误的。因为FileWriter重写与否,是根据构造函数中的参数来确定。

FileWriter源码中:

public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
第二个参数决定了重写还是追加。write()和append()源码如下:

public void write(String str) throws IOException {
write(str, 0, str.length());
}

public Writer append(char c) throws IOException {
write(c);
return this;
}
可以发现append()函数本质上直接调用了write(),只是多返回了一个Writer对象的引用。

BufferReader/BufferWriter使用:

Reader re = new FileReader(file);
BufferedReader bReader = new BufferedReader(re);
bReader.readLine();

Writer writer = new FileWriter(new File("E:\\test123.txt"));
BufferedWriter bWriter = new BufferedWriter(writer);
bWriter.write("Hello World~");
bWriter.close();
BufferReader/BufferWriter也使用了一个缓冲区,减少了一定程度上的IO次数,所以要比Reader/Writer快一些。同时也具有mark()和reset()函数。

mark(int readlimit):调用该函数的时候记录一下标记位置,在下次使用reset()的时候使读取的位置重新回到该标记位置,然后继续往后读。如果在标记以后读取的长度大于readlimit,则上次标记位置失效。

reset():将游标重置到上次标记的位置,重新读取。

字节流:

FileInputStream/FileOutputStream使用:

// 从文件中读取
File file = new File("E:\\class.txt");
InputStream iStream = new BufferedInputStream(new FileInputStream(file));
byte [] bs = new byte [10240];
try {
iStream.read(bs);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(new String(bs));
//写入文件
File file1 = new File("E:\\test1.txt");
String str = "HelloWorld";
FileOutputStream fOutputStream = new FileOutputStream(file1);
fOutputStream.write(str.getBytes());
fOutputStream.close();
BufferInputStream/BufferOutputStream使用类似:

File file = new File("E:\\class.txt");
BufferedInputStream bStream = new BufferedInputStream(new FileInputStream(file));
byte [] bs = new byte [10240];
try {
bStream.read(bs);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(new String(bs));

File file1 = new File("E:\\test1.txt");
BufferedOutputStream bStream2 = new BufferedOutputStream(new FileOutputStream(file1));
String str = "HelloWorld~~~";
bStream2.write(str.getBytes());
bStream2.close();
注:字节流的类均为Inputstream/OutputStream的子类,所以均实现了mark(int readlimit)和reset()。同时,BufferInputStream/BufferOutputStream比FileInputStream/FileOutputStream效率要高一点。

字符流和字节流的选用:

字节流:硬盘中存储的音频文件、图片、歌曲,所有的硬盘上保存文件或进行传输或者实现拷贝的时候,应该选择字节流

字符流:处理中文使用字节流会乱码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: