希望您在看这篇博客之前,知道Java IO技术,至少写过IO操作的Demo!
另外建议您看看: Java IO:IO流中的flush方法
这篇博客,主要使用Socket实例(很简单的小例子)来引出问题,然后在探讨问题。
1. Socket服务端
package mark.zhang;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket server = new ServerSocket(3000);
Socket socket = server.accept();
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = br.readLine();
System.out.println("server receive info: " + info);
}
}
2. Socket客户端
package mark.zhang;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
Socket client = new Socket("127.0.0.1", 3000);
OutputStream os = client.getOutputStream();
PrintWriter pw = new PrintWriter(os, true);
pw.print("Hello,Server");
pw.close();
// pw.println("Hello,Server");
}
}
代码很简单,主要是客户端向服务端发送一个字符串,服务端将接收到的信息打印出来。
上面代码,运行(先运行Server.java后运行Client.java)之后,一切正常!
经过Debug,我发现,调用层次:
PrintWriter的 close()方法 ---> BufferedWriter的close()方法 ---> OutputStreamWriter的close()方法 ---> StreamEncoder的close()方法
BufferedWriter的close()方法源码:
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try {
flushBuffer();
} finally {
out.close();
out = null;
cb = null;
}
}
OutputStreamWriter的close()方法源码:
public void close() throws IOException {
se.close();
}
StreamEncoder的close()方法源码可以参看
http://blog.csdn.net/androidbluetooth/article/details/6460726这篇文章的代码。
那么,我们做点调整,改变这些正常反应吧!修改客户端代码(注释掉pw.close()):
package mark.zhang;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
Socket client = new Socket("127.0.0.1", 3000);
OutputStream os = client.getOutputStream();
PrintWriter pw = new PrintWriter(os, true);
pw.print("Hello,Server");
// pw.close();
// pw.println("Hello,Server");
}
}
服务端打印结果:
server receive info: null
也就是说,没有接收到任何信息。也就是说,这种方式在服务端无法接收到信息。
恶作剧一把之后,我们再次修改代码,如下:
package mark.zhang;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
Socket client = new Socket("127.0.0.1", 3000);
OutputStream os = client.getOutputStream();
PrintWriter pw = new PrintWriter(os, true);
//pw.print("Hello,Server");
//pw.close();
pw.println("Hello,Server");
}
}
ok,服务端可以接收到信息。看看PrintWriter类的println方法源码:
public void println(String x) {
synchronized (lock) {
print(x);
println();
}
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
public void println() {
newLine();
}
newLine()就是加入一个回车符:
private void newLine() {
try {
synchronized (lock) {
ensureOpen();
out.write(lineSeparator);
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
lineSeparator定义:
lineSeparator = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
服务端的readLine()方法,遇到回车符就读一次数据(一行一行的读)。所以服务端可以收到信息。
3. 研究一下readLine
再次修改Client.java代码:
package mark.zhang;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
Socket client = new Socket("127.0.0.1", 3000);
OutputStream os = client.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeBytes("Hello,Server1");
dos.writeBytes("\n");
dos.writeBytes("Hello,Server2");
//dos.close();
}
}
服务端接收信息:
server receive info: Hello,Server1
说明,没有接收到Hello,Server2。这就说明,readLine遇到回车就算读完信息。
关于readLine()方法的其它用法,见下代码:
package csdn.zhwx;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class BufferedReaderTest {
public static void getFile(String readFilePath, String readFileName,
String writeFilePath, String writeFileName) {
File reaFile = null;
FileInputStream fis = null;
BufferedReader bReader = null;
File writeFile = null;
FileOutputStream fos = null;
BufferedWriter bWriter = null;
try {
if (!(readFileName == null || readFileName.length() <= 0)) {
reaFile = new File(readFilePath + readFileName);
fis = new FileInputStream(reaFile);
// bReader = new BufferedReader(new InputStreamReader(fis,"GBK"));//指定GBK编码,一般用在汉化windows上。
// bReader = new BufferedReader(new InputStreamReader(fis));//默认编码,和系统编码一致。linux为UTF-8
bReader = new BufferedReader(
new InputStreamReader(fis, "UTF-8"));// 指定UTF-8编码
writeFile = new File(writeFilePath, writeFileName);
fos = new FileOutputStream(writeFile);
// bWriter = new BufferedWriter(new OutputStreamWriter(fos));//默认编码,和系统编码一致。linux为UTF-8
bWriter = new BufferedWriter(new OutputStreamWriter(fos,
"UTF-8"));// 指定UTF-8编码
String str = null;
while ((str = bReader.readLine()) != null) {// 该方法不会将读取到的换行\n写到文件中
// System.out.println(str);
// 要自己手动加\n
bWriter.write(str + "\n");
/*bWriter.write(str);
bWriter.newLine();*/
// 不刷新的话,文件不会有内容
bWriter.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
try {
fis.close();
bReader.close();
fos.close();
bWriter.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} finally {
try {
fis.close();
bReader.close();
fos.close();
bWriter.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
public static void main(String[] args) {
getFile("/home/zhihui/Downloads/", "hello.txt",
"/home/zhihui/Downloads/", "copyFormHello.txt");
//linux下测试
/*当前JRE:1.6.0_23
当前JVM的默认字符集:UTF-8*/
System.out.println("当前JRE:" + System.getProperty("java.version"));
System.out.println("当前JVM的默认字符集:" + Charset.defaultCharset());
}
}