➤ Java 输入输出IO流 全部导航
文章目录
- 乱码转换【转换流】
- InputStreamReader
- OutputStreamWriter
- 打印流:
- PrintStream
- PrintWriter
类型 | 默认设备 | |
---|---|---|
System.in 标准输入 | InputStream | 键盘 |
System.out 标准输出 | PrintStream | 显示器 |
System类的 public final static InputStream in = null;
public final static PrintStream in = null;
标准输入:
System.in 编译类型 InputStream
System.in 运行类型 BufferedInputStream
System.out.print(System.in.getClass());
输出为 class java.io.BufferedInputStream
标准输出:
System.out 编译类型 PrintStream
System.out 运行类型 PrintStream
乱码转换【转换流】
字节流 ----> 字符流 即 转换流
通过一个例子引出乱码转换问题:
- 使用BufferedReader 对象读取一个txt文件
- txt文件默认编码方式是 UTF-8
- 由图中可以看到是正常读取的,没有问题
但是 把文件编码方式改成 ANSI 之后,再进行读取时:
发现出现了乱码,没有正常读取到文件内容;
可以这样解决:
- 将字节流以指定编码方式读取(GBK、UTF-8、ISO8859、ANSI等等);
- 再通过转换流 转换为字符流 即可;
转换流有:
- InputStreamReader
- OutputStreamWriter
当处理纯文本数据时,使用字符流效率更高,并且可以有效解决中文乱码问题,所以建议将字节流转换为字符流:
InputStreamReader
- Reader的子类,可以将InputStream(字节流)包装成Reader(字符流);
InputStreamReader的构造器:(属于字符流)
InputStreamReader(InputStream) 字节流转换为字符流
InputStreamReader(InputStream,Charset) 以指定编码方式Charset,字节流转换为字符流
InputStreamReader(InputStream,CharsetDecoder) 给定一个字符解码器CharsetDecoder,字节流转换为字符流
InputStreamReader(InputStream,String) 指定编码名称,字节流转换为字符流
示例: 将字节流FileInputStream包装成字符流InputStreamReader,对文件进行按UTF-8编码读取,进而在包装成 BufferedReader
/*
演示使用InputStreamReader转换流解决中文乱码问题
将字节流FileInputStream转成字符流InputStreamReader,指定编码GBK/UTF-8
*/
public static void main(String[] args) throws Exception{
String filePath = "d:\\hello.txt";
//1.把FileInputStream转成InputStreamReader (字节流转为字符流)
//2.指定编码 gbk
InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "GBK");
//3.把InputStreamReader传入BufferedReader
BufferedReader br = new BufferedReader(isr);
/*
为了简化 可以将 2 和 3 合在一起
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "GBK"));
*/
//4.读取
String s = br.readLine();
System.out.println("读取内容:\n"+s);
//5.关闭外层流
br.close();
}
可以看出 运行结果读取正常:
OutputStreamWriter
- Writer的子类,可以将OutputStream(字节流)包装成Writer(字符流);
类比 InputStream 有如下关系 及 构造器:
示例:将字节流 FileOutputStream 包装成 字符流 OutputStreamWriter,对文件进行写入(按gbk编码方式,也可以指定其他。如 utf-8)
/*
演示 OutputStreamWriter 使用
把 FileOutputStream 字节流 转为 字符流 OutputStreamWriter
指定编码 gbk/utf-8/utf8
*/
public static void main(String[] args) throws Exception{
String filePath = "d:\\yes.txt";//提前创建
String charset = "utf8";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath),charset);
osw.write("Hi 祝你天天开心!");
osw.close();
System.out.println("按照"+charset+"保存文件成功");
}
运行结果:
改变编码方式:
打印流:
打印流只有输出流,没有输入流
PrintStream & PrintWriter(两者区别在文章末尾)
PrintStream
/*
演示PrintStream(字节打印流/输出流)
*/
public static void main(String[] args) throws IOException {
PrintStream out = System.out;
//在默认情况下PrintStream输出数据的位置是标准输出即显示器
/*
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
*/
out.print("Java");
//因为print底层使用的是write方法,所以可以直接调用write进行打印/输出
out.write("你好".getBytes());
out.close();
//可以修改打印输出流的位置/设备
/*
public static void setOut(PrintStream out) {
checkIO();
setOut0(out); //native()方法,修改out
}
*/
//输出到文件
System.setOut(new PrintStream("d:\\hello.txt"));
System.out.println("Hello World!");//输出到文件
}
PrintWriter
// 演示 PrintWriter 使用方式
public static void main(String[] args) throws IOException {
PrintWriter printWriter = new PrintWriter(new FileWriter("d:\\hello.txt"));
printWriter.print("你好Java");
printWriter.close();//如果不关闭,就无法写入
}
PrintStream 和 PrintWriter 的区别:
- Stream用于二进制文件(非文本) ,Writer/Reader用于文本文件(虽然也是二进制,不过是按照一定的字符编码规则,不像前者) ,当然Stream也可用于文本,只不过比Writer/Reader来的麻烦;
- PrintStream主要操作byte流,而PrintWriter用来操作字符流。读取文本文件时一般用后者。
- Java的一个字符(char)是16bit的,一个byte是8bit的。PrintStream是写入一串8bit的数据的,PrintWriter是写入一串16bit的数据的。String缺省是用UNICODE编码,是16bit的。因此用PrintWriter写入的字符串,跨平台性会好一些,PrintStream的可能会出现字符集乱码。
- PrintStream是OutputStream的子类,PrintWriter是Writer的子类,两者处于对等的位置上,所以它们的API是非常相似的;二者区别不大;
- PrintStream类是过滤器类中一个不可忽视的成员,最基本的标准输出就要借助于它——我们常用的System.out变量就是PrintStream实例。与之对应的字符流类是PrintWriter类。
- PrintWriter类是JDK1.1版增加了与字节流I/O相对应的字符流I/O。但是,为了保持兼容性,原先的类几乎没有改动。再加之调试的需要,PrintStream类被保留,并且System类中的成员变量out、err仍作为它的对象。然而,PrintWriter用于大多数输出比PrintStream更为合适。因此1.1版的API中建议新开发的代码使用PrintWriter类,并将PrintStream类的两个构造函数标记为过时。这样,虽然使用System.out输出不会产生问题,在程序中创建新的PrintStream对象时却会产生编译时的警告。