【转-汇总】IO流基础知识及Socket 流传输乱码的问题
Java代码
- read();??
- read(byte[]?b)?;??
- read(byte[]?b,?int?off,?int?len)?;??
?
用于从输入流中读取字节。
?
OutputStream提供的最重要的方法是:
?
Java代码- write(int?b);??
- write(byte[]?b);??
- write(byte[]?b,?int?off,?int?len)???
?
用于将字节写入输出流。
?
字节流处理类概述:
?
字节流的处理类有很多,他们都继承自InputStream或者OutputStream抽象类。
?
输入流:
?
先谈谈输入流,输入流中跟数据源直接接触的类有:FileInputStream和ByteArrayInputStream,他们分别实现了从文件或者内存中的字节数组读入数据到输入流。
?
其他的输入流处理类都是装饰类—ecorator模式),下面对他们进行一下简单介绍:
?
BufferedInputStream: 提供了缓冲功能。
DataInputStream: 允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
PipedInputStream: 允许以管道的方式来处理流。当连接到一个PipedOutputStream后,它会读取后者输出到管道的数据。
PushbackInputStream: 允许放回已经读取的数据。
SequenceInputStream: 能对多个inputstream进行顺序处理。
?
输出流:
?
基本上每个输入流类都有一个相应的输出流类,提供相应的输出流处理。
同样,跟数据目的地直接接触的类有:FileOutputStream和ByteArrayOutputStream,前者实现了把数据流写入文件的功能,后者实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用Java代码
- read(char[]?cbuf);??
- read(char[]?cbuf,?int?off,?int?len);??
- read(CharBuffer?target);??
?
他们提供了从流中读取数据到字符数组或者CharBuffer的功能。
?
Writer提供的重要方法有:
?
Java代码- write(char[]?cbuf);??
- write(char[]?cbuf,?int?off,?int?len);??
- write(int?c);??
- write(String?str);??
- write(String?str,?int?off,?int?len);??
?
他们提供了把字符、字符数组或者字符串写入流中的功能。
?
字符流处理类概述:
?
输入流:
?
跟数据源直接接触的类:
CharArrayReader: 从内存中的字符数组中读入数据,以对数据进行流式读取。
StringReader:从内存中的字符串读入数据,以对数据进行流式读取。
FileReader:从文件中读入数据。注意这里读入数据时会根据JVM的默认编码对数据进行内转换,而不能指定使用的编码。所以当文件使用的编码不是JVM默认编码时,不要使用这种方式。要正确地转码,使用InputStreamReader。
?
装饰类:
BufferedReader:提供缓冲功能,可以读取行:readLine();
LineNumberReader: 提供读取行的控制:getLineNumber()等方法。
InputStreamReader: 字节流通向字符流的桥梁:它使用指定的Java代码
- is?=?new?BufferedInputStream(new?FileInputStream("res/input.data"));??
- assertTrue(is.available()?>?0);??
- assertTrue(is.markSupported());??
- ??
- //?The?read?limit?has?no?effect.??
- is.mark(0);??
- ??
- int?first?=?is.read();??
- int?second?=?is.read();??
- ??
- is.reset();??
- int?firstAgain?=?is.read();??
- int?secondAgain?=?is.read();??
- ??
- assertEquals(first,?firstAgain);??
- assertEquals(second,?secondAgain);??
?
Writer或者OutputStream中的flush(): 刷新该流的缓冲,用于确保数据的输出。
?
close(): 关闭流并释放与之关联的所有系统资源。
?
********************************************分割线*******************************************
了解了上面的概念之后,下面就开始讨论乱码的问题。
下面一段也是摘自网络,网址忘记了。
?
假设新建一个字符串如下:
String?strMsg = new String("消息".getBytes("GBK"),"UTF-8");
这种方式只是在JVM内部转换,那么一旦涉及到流比如数据库、文件等就要使用java IO进行转换。
也就是说JVM内部编码unicode和外部os编码的转换。
如果直接使用***Writer.write(strMsg)等等,在接收方会有一定概率出现乱码,至于乱码的产生和很多因素有关,比如页面编码,不同JVM或OS编码不同等。
使用下面方式就没有问题了
?
字符流方式发送
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream),"UTF-8")),false);
字节流方式发送
PrintStream ps = new PrintStream(socket.getOutputStream(),false,"UTF-8");
false表示手动pw.flush();