希望您在看这篇博客之前,知道Java IO技术,至少写过IO操作的Demo!
另外建议您看看: Java IO:IO流中的flush方法
这篇博客,主要使用Socket实例(很简单的小例子)来引出问题,然后在探讨问题。
1. Socket服务端
[java] view plain copy print ?
- 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);
- }
-
- }
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客户端
[java] view plain copy print ?
- 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();
-
- }
- }
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()方法源码:
[java] view plain copy print ?
- public void close() throws IOException {
- synchronized (lock) {
- if (out == null) {
- return;
- }
- try {
- flushBuffer();
- } finally {
- out.close();
- out = null;
- cb = null;
- }
- }
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try {
flushBuffer();
} finally {
out.close();
out = null;
cb = null;
}
}
OutputStreamWriter的close()方法源码:
[java] view plain copy print ?
- public void close() throws IOException {
- se.close();
- }
public void close() throws IOException {
se.close();
}
StreamEncoder的close()方法源码可以参看 http://blog.csdn.net/androidbluetooth/article/details/6460726这篇文章的代码。
那么,我们做点调整,改变这些正常反应吧!修改客户端代码(注释掉pw.close()):
[java] view plain copy print ?
- 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");
-
-
- }
- }
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");
}
}
服务端打印结果:
[java] view plain copy print ?
- server receive info: null
server receive info: null
也就是说,没有接收到任何信息。也就是说,这种方式在服务端无法接收到信息。
恶作剧一把之后,我们再次修改代码,如下:
[java] view plain copy print ?
- 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.println("Hello,Server");
- }
- }
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方法源码:
[java] view plain copy print ?
- public void println(String x) {
- synchronized (lock) {
- print(x);
- println();
- }
public void println(String x) {
synchronized (lock) {
print(x);
println();
}
[java] view plain copy print ?
- public void print(String s) {
- if (s == null) {
- s = "null";
- }
- write(s);
- }
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
[java] view plain copy print ?
- public void println() {
- newLine();
- }
public void println() {
newLine();
}
newLine()就是加入一个回车符:
[java] view plain copy print ?
- 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;
- }
- }
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定义:
[java] view plain copy print ?
- lineSeparator = (String) java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction("line.separator"));
lineSeparator = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
服务端的readLine()方法,遇到回车符就读一次数据(一行一行的读)。所以服务端可以收到信息。
3. 研究一下readLine
再次修改Client.java代码:
[java] view plain copy print ?
- 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");
-
- }
- }
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();
}
}
服务端接收信息:
[java] view plain copy print ?
- server receive info: Hello,Server1
server receive info: Hello,Server1
说明,没有接收到Hello,Server2。这就说明,readLine遇到回车就算读完信息。
关于readLine()方法的其它用法,见下代码:
[java] view plain copy print ?
- 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, "UTF-8"));
-
- writeFile = new File(writeFilePath, writeFileName);
- fos = new FileOutputStream(writeFile);
-
- bWriter = new BufferedWriter(new OutputStreamWriter(fos,
- "UTF-8"));
-
- String str = null;
- while ((str = bReader.readLine()) != null) {
-
-
- bWriter.write(str + "\n");
-
-
-
-
-
- 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");
-
-
-
-
- System.out.println("当前JRE:" + System.getProperty("java.version"));
- System.out.println("当前JVM的默认字符集:" + Charset.defaultCharset());
- }
- }