首先需要明确的一点是输入流输出流的输入输出是站在内存的角度看的,读取文件,把文件内容写到内存中,是输入流;写文件,把内存中的数据写到文件中,是输出流。

IO操作主要有4个抽象类:

字节输入输出流:InputStream、OutputStream,操作的是字节byte。

字符输入输出流:Reader、Writer,操作的是字符char。

最常用的子类有FileInputStream 、FileOutputStream、InputStreamReader、OutputStreamWriter、FileReader、FileWriter、BufferedReader、BufferedWriter

FileInputStream是InputStream的直接子类,其最常用的构造器是FileInputStream(File file),参数传一个File对象,即获得了此File对象对应的字节输入流,常用的方法是:int read(byte b[]);从字节输入流中读取数据到字节数组中,在读的过程中会阻塞线程,返回值是实际读取到的字节的长度,如果什么都没读到,会返回-1。示例:

public static void main(String[] args) {
File file = new File("D:/tmp.txt");
InputStream input = null;
try {
input = new FileInputStream(file);
//每次读1024个字节
byte[] b = new byte[1024];
int len = -1;
while ((len = input.read(b)) != -1) {
System.out.println(len);
String info = new String(b, 0, len);
System.out.println(info);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

需要注意的是,流资源是很昂贵的资源,用完之后要关闭。通常在finally块中关闭。

FileOutputStream是OutputStream的直接子类,其最常用的构造器有两个,用于得到一个File对象对应的字节输出流:

FileOutputStream(File file);只需传一个File对象

FileOutputStream(File file, boolean append);不仅要传一个File对象,还需要传一个布尔值,如果这个布尔值是true的话,则会在原文件中追加内容,如果是false的话,效果等同于第一个构造器,即会覆盖原文件

字节输出流常用的方法是write(byte[] b);把b字节数组所有的字节写到输出流中。示例:

public static void main(String[] args) {
File file = new File("D:/tmp.txt");
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write("welcome to u".getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (output!= null) {
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

值得注意的是,字节输出流write完之后不用调flush方法去手动刷缓存区,实测,只要执行完write()方法之后,文件中就会有内容。当然最终还是得调用close方法关闭流,免得资源浪费。

如果想在文件中输入换行,可以用String separator = System.getProperty("line.separator");拿到换行符,在不同的系统中换行符是不一样的,所以不能写死,必须得通过这种方式得到。得到换行符之后,想换行就简单了,调用字节输出流的write(separator.getBytes())方法就好了。示例:

public static void main(String[] args) {
String separator = System.getProperty("line.separator");
File file = new File("D:/tmp.txt");
OutputStream output = null;
try {
output = new FileOutputStream(file, true);
output.write((separator + "thank u").getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (output != null) {
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

InputStreamReader是Reader的直接子类,是字节输入流转变成字符输入流的桥梁,也被称为转换流。主要用到的构造器有两个:

InputStreamReader(InputStream in);传入一个InputStream对象,使用当前IDE workspace的编码格式

InputStreamReader(InputStream in, String charsetName);传入一个InputStream对象和一个指定编码集的字符串。建议使用这种方式,尽量让结果与IDE的设置无关,这样代码具有可移植性。

最常用的方法还是 int read(char cbuf[]);不过注意的是,这里操作的是字符数组了,从字符输入流中读取数据到字符数组中,在读的过程中会阻塞线程。

示例:

public static void main(String[] args) {
InputStream input = null;
InputStreamReader inputStreamReader = null;
try {
input = new FileInputStream(new File("/tmp.txt"));
inputStreamReader = new InputStreamReader(input, "GBK");
char[] cbuf = new char[10240];
int len = -1;
while ((len = inputStreamReader.read(cbuf)) != -1) {
System.out.println(len);
String str = new String(cbuf, 0, len);
System.out.println(str);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStreamReader != null) {
try {
inputStreamReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

在简体中文windows系统上创建文本文件,打开,另存为时发现编码是ANSI,ANSI在简体中文windows系统上就是GBK,在繁体中文Windows系统上是Big5。

上例中创建InputStreamReader实例时用了InputStreamReader(InputStream in, String charsetName)构造器,指定读取文件时用GBK解码(数据在计算机中存储的是二进制,按照GBK规则解码成我们能理解的字符)。如果不指定GBK,则会因为我们一般把IDE的workspace的编码设为UTF-8而乱码。(实测)

OutputStreamWriter是Writer的直接子类,是字节输出流转变成字符输出流的桥梁,也称为转换流。常用的构造器也有两个:

OutputStreamWriter(OutputStream out);

OutputStreamWriter(OutputStream out, String charsetName);推荐用这种,在创建时指定编码格式,否则会用IDE workspace的编码格式。

常用的方法是:

write(char cbuf[], int off, int len);用于从文件中读取数据并保存到另一文件的情况

write(String str, int off, int len);用于想把一个字符串保存到一个文件的情况

flush();把数据从缓冲区中刷新到指定文件中。不管是用的write()方法的哪种重载,执行完之后,数据是在缓冲区中(在内存中),需要把缓冲区中的数据手动刷到指定目的地。close()方法内部也调用了flush()方法,如果用close()刷数据的话,刷之后会关闭流,流关闭后再write()就会报错了,所以根据实际需求选择合适的刷新方法。其实,最好不要在最后才刷缓冲区,因为如果数据很大的话,不刷缓冲区会占用很多内存(在内存存储者那些数据),即时不报内存溢出错误也是属于很严重的资源浪费。

示例:

public static void main(String[] args) {
OutputStreamWriter writer = null;
InputStreamReader reader = null;
try {
writer = new OutputStreamWriter(new FileOutputStream(new File("/tmp.txt")), "UTF-8");
reader = new InputStreamReader(new FileInputStream(new File("/1.txt")), "GBK");
char[] cbuf = new char[1024];
int len = -1;
while ((len = reader.read(cbuf)) != -1) {
writer.write(cbuf, 0, len);
writer.flush();
}
writer.write("你好吗?");
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

上例中,1.txt是在windows系统下建的一个文件文件,随便写点内容。上例代码是将1.txt的内容复制到tmp.txt文件中,并在后面追加了一些内容。

FileReader是InputStreamReader的子类,与InputStreamReader只有一点不同,那就是固定了编码为当前IDE workspace的编码集,改不了。不推荐使用。同理,FileWriter也不推荐使用。

public static void main(String[] args) {
FileReader reader = null;
FileWriter writer = null;
try {
reader = new FileReader(new File("/1.txt"));
writer = new FileWriter(new File("/2.txt"));
char[] cbuf = new char[1024];
int len = -1;
while ((len = reader.read(cbuf)) != -1) {
writer.write(cbuf, 0, len);
writer.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

上例中用了FileReader、FileWriter,复制1.txt的内容到2.txt文件中。1.txt是在简体中文windows系统上创建的一个文本文件,GBK编码,上面代码运行完后,查看2.txt的内容,不会乱码。但是如果把1.txt另存为UTF-8编码的,再运行上面代码,2.txt内容会乱码,只要不改变IDE的workspace的编码,问题就解决不了。所以还是推荐使用InputStreamReader、OutputStreamWriter。

如果使用字节流的话,没有必要使用缓冲流(对应的缓冲流有BufferedInputStream、BufferedOutputStream)。使用字符流时可以使用缓冲字符流BufferedReader、BufferedWriter,其中BufferedReader的地位同InputStreamReader一样,也是Reader的直接子类,BufferedWriter的地位同OutputStreamWriter一样,也是Writer的直接子类。

BufferedReader常用的构造器是BufferedReader(Reader in);创建一个默认大小(8192字符)缓冲区的缓冲字符输入流对象,需要传入一个Reader对象,这个Reader对象通常是一个InputStreamReader实例。

BufferedReader对象常用的方法除了read()的各种重载外,最重要的是多了一个String readLine()方法,用来读取一行,返回值是这一行的数据,如果读到文件尾了,会返回null。其实,如果不逐行读取的话,也没必要用缓冲字符流,用转换流就足够了。

BufferedWriter常用的构造器是BufferedWriter(Writer out);创建一个默认大小(8192字符)缓冲区的缓冲字符输出流对象,需要传入一个Writer对象,这个Writer对象通常是一个InputStreamWriter实例。

BufferedWriter对象常用的方法除了write()的各种重载外,最重要的是多了一个newLine()方法,用于输出一个换行,相当于调用字节输出流对象的write(System.getProperty("line.separator").getBytes())方法或者调用字符输出流对象的write(System.getProperty("line.separator"))方法。

缓冲流用法示例:

public static void main(String[] args) {
BufferedReader reader = null;
BufferedWriter writer = null;
String str = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(new File("/1.txt")), "GBK"));
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/2.txt"), "UTF-8"));
while ((str = reader.readLine()) != null) {
writer.write(str);
writer.newLine();
writer.flush();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (writer != null) {
try {
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

上例中,逐行读取文件,并逐行写到新文件,且原文件是GBK编码的,新文件是UTF-8编码的。

io基础(字节流、字符流、转换流、缓冲字符流)的更多相关文章

  1. 零基础学习java------day17------缓冲字节流,转换字节流,简化流,缓冲字符流,序列化和对象流

    1. 缓冲字节流 缓冲区:缓冲区实质上是一个数组.通常它是一个字节数组,但是也可以使用其他种类的数组.但是一个缓冲区不 仅仅 是一个数组.缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程 ...

  2. day4学python 字符编码转换+元组概念

    字符编码转换+元组概念 字符编码转换 #coding:gbk //此处必声明 文件编码(看右下角编码格式) #用来得到python默认编码 import sys print(sys.getdefaul ...

  3. Java 基础 IO流(转换流,缓冲)

    一,前言 在学习字符流(FileReader.FileWriter)的时候,其中说如果需要指定编码和缓冲区大小时,可以在字节流的基础上,构造一个InputStreamReader或者OutputStr ...

  4. 01 语言基础+高级:1-8 File类与IO流_day10【缓冲流、转换流、序列化流】

    day10[缓冲流.转换流.序列化流] 主要内容 缓冲流 转换流 序列化流 打印流 教学目标 能够使用字节缓冲流读取数据到程序 能够使用字节缓冲流写出数据到文件 能够明确字符缓冲流的作用和基本用法 能 ...

  5. java基础45 IO流技术(输入字符流/缓冲输入字符流)

    一.输入字符流 1.1.输入字符流体系 ------| Reader:输入字符流的基类(抽象类)  ----------| FileReader:向指定文件读取数据的输入字符流(把硬盘上的数据读取到程 ...

  6. Java基础知识强化之IO流笔记38:字符流缓冲流之BufferedWriter / BufferedReader使用

    1. 字符流缓冲流: 字符流为了高效读写,也提供了对应的字符缓冲流. BufferedWriter:字符缓冲输出流 BufferedReader:字符缓冲输入流 2. BufferedWriter使用 ...

  7. IO流----转换流、缓冲流

    打开一个文本文件,另存为: Ansi就是系统默认编码(就是gbk) 建一个编码是utf-8的txt文件, 例: import java.io.FileWriter; import java.io.IO ...

  8. IO(字节流、字符流)

      第1章 字节流 在前面的学习过程中,我们一直都是在操作文件或者文件夹,并没有给文件中写任何数据.现在我们就要开始给文件中写数据,或者读取文件中的数据. 1.1 字节输出流OutputStream ...

  9. (19)IO流之字符流FileReader和FileWriter,缓冲字符流---缓冲输入字符流BufferedReader和缓冲输出字符流BufferedWriter

    字符流,读取的文件是字符的时候,有两个基类一个是Reader,一个是Writer这有点拟人的感觉,人直接看懂的是文字 字符流 字节流:读取的是文件中的二进制字节流并不会帮你转换成看的懂得字符 字符流: ...

随机推荐

  1. Windows Live Writer 使用指南

    一.简介 Windows Live Writer 是一个强大的离线博客编辑工具,通过它可以离线编辑内容丰富的博文,除了自身强大的编辑功能之外,还提供了接口,让其它开发人员通过插件提供工具自身没有提供的 ...

  2. 22、linux的ssh互信配置

    转载:https://blog.csdn.net/hrn1216/article/details/51568830 https://blog.csdn.net/u013144287/article/d ...

  3. ARC073D Simple Knapsack

    传送门 题目大意 给你n个物品,你有一个容量为W的背包,每一个物品都有它的重量和价值,让你从n个中选取若干个,使得总重量不超过背包的上限,而且使得价值最大. 分析 首先我们不难发现由于W很大,所以这并 ...

  4. apache隐藏入口文件index.php

    LoadModule rewrite_module modules/mod_rewrite.so

  5. 【IMOOC学习笔记】多种多样的App主界面Tab实现方法(二)

    Fragment实现Tab 首先把activity_main.xml 文件中的ViewPager标签改成Fragment标签 <FrameLayout android:id="@+id ...

  6. linux手动安装配置 mysql5.7

    本文原出处地址  https://www.cnblogs.com/mujingyu/p/7689116.html 一.安装前的检查 1.1 检查 linux 系统版本 [root@localhost ...

  7. js 代码收集

    //获取image src路径 $(".userImg").click(function(){ var imgsrc = $(this).attr("src") ...

  8. UWP&WP8.1 基础控件—TextBlock和TextBox

    TextBlock:文本展示控件,有着强大的功能 TextBox:文本输入控件. 这两个控件是最为常用的基础控件. TextBlock 基础用法: 打开一个UWP项目,在XAML设计页面你可以从工具箱 ...

  9. Android emulator中C代码的调试——gdb/gdbservers时遇到的坑

    版权声明:本文为博主原创文章,未经博主允许不得转载. 先写个helloworld吧,在Android源码树中创建文件夹external/helloworld,加入文件: // helloworld.c ...

  10. 「BZOJ 2440」完全平方数「数论分块」

    题意 \(T\)组数据,每次询问第\(k\)个无平方因子的数(\(1\)不算平方因子),\(T\leq 50,k\leq 10^9\) 题解 \(k\)的范围很大,枚举肯定不行,也没什么奇妙性质,于是 ...