其实绝大多数编程语言之间的通信原理是一样的这边文章来看一下java是如何进行文件传输的
建议先看 Client 类,再看 Server 类。
- import java.io.*;
- import java.net.ServerSocket;
- import java.net.Socket;
- /**
- * 简单的文件发送与接收示例
- */
- public class FileTrasmission {
- //程序入口
- public static void main(String[] args) throws Exception {
- int port = 7788;
- new Server(port, "c://save//").start();
- new Client().sendFile("127.0.0.1", port, "c://迷失在康熙末年.txt");
- }
- }
- /**
- * 接收端。可同时接收多个发送端发来的文件。但如果发来的文件是同名的话那就乱了。
- */
- class Server {
- private int listenPort;
- private String savePath;
- /**
- * 构造方法
- *
- * @param listenPort 侦听端口
- * @param savePath 接收的文件要保存的路径
- *
- * @throws IOException 如果创建保存路径失败
- */
- Server(int listenPort, String savePath) throws IOException {
- this.listenPort = listenPort;
- this.savePath = savePath;
- File file = new File(savePath);
- if (!file.exists() && !file.mkdirs()) {
- throw new IOException("无法创建文件夹 " + savePath);
- }
- }
- // 开始侦听
- public void start() {
- new ListenThread().start();
- }
- // 网上抄来的,将字节转成 int。b 长度不得小于 4,且只会取前 4 位。
- public static int b2i(byte[] b) {
- int value = 0;
- for (int i = 0; i < 4; i++) {
- int shift = (4 - 1 - i) * 8;
- value += (b[i] & 0x000000FF) << shift;
- }
- return value;
- }
- /**
- * 侦听线程
- */
- private class ListenThread extends Thread {
- @Override
- public void run() {
- try {
- ServerSocket server = new ServerSocket(listenPort);
- // 开始循环
- while (true) {
- Socket socket = server.accept();
- new HandleThread(socket).start();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 读取流并保存文件的线程
- */
- private class HandleThread extends Thread {
- private Socket socket;
- private HandleThread(Socket socket) {
- this.socket = socket;
- }
- @Override
- public void run() {
- try {
- InputStream is = socket.getInputStream();
- readAndSave(is);
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- socket.close();
- } catch (IOException e) {
- // nothing to do
- }
- }
- }
- // 从流中读取内容并保存
- private void readAndSave(InputStream is) throws IOException {
- String filename = getFileName(is);
- int file_len = readInteger(is);
- System.out.println("接收文件:" + filename + ",长度:" + file_len);
- readAndSave0(is, savePath + filename, file_len);
- System.out.println("文件保存成功(" + file_len + "字节)。");
- }
- private void readAndSave0(InputStream is, String path, int file_len) throws IOException {
- FileOutputStream os = getFileOS(path);
- readAndWrite(is, os, file_len);
- os.close();
- }
- // 边读边写,直到读取 size 个字节
- private void readAndWrite(InputStream is, FileOutputStream os, int size) throws IOException {
- byte[] buffer = new byte[4096];
- int count = 0;
- while (count < size) {
- int n = is.read(buffer);
- // 这里没有考虑 n = -1 的情况
- os.write(buffer, 0, n);
- count += n;
- }
- }
- // 读取文件名
- private String getFileName(InputStream is) throws IOException {
- int name_len = readInteger(is);
- byte[] result = new byte[name_len];
- is.read(result);
- return new String(result);
- }
- // 读取一个数字
- private int readInteger(InputStream is) throws IOException {
- byte[] bytes = new byte[4];
- is.read(bytes);
- return b2i(bytes);
- }
- // 创建文件并返回输出流
- private FileOutputStream getFileOS(String path) throws IOException {
- File file = new File(path);
- if (!file.exists()) {
- file.createNewFile();
- }
- return new FileOutputStream(file);
- }
- }
- }
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 简单的文件发送与接收示例
*/
public class FileTrasmission {
//程序入口
public static void main(String[] args) throws Exception {
int port = 7788;
new Server(port, "c://save//").start();
new Client().sendFile("127.0.0.1", port, "c://迷失在康熙末年.txt");
}
}
/**
* 接收端。可同时接收多个发送端发来的文件。但如果发来的文件是同名的话那就乱了。
*/
class Server {
private int listenPort;
private String savePath;
/**
* 构造方法
*
* @param listenPort 侦听端口
* @param savePath 接收的文件要保存的路径
*
* @throws IOException 如果创建保存路径失败
*/
Server(int listenPort, String savePath) throws IOException {
this.listenPort = listenPort;
this.savePath = savePath;
File file = new File(savePath);
if (!file.exists() && !file.mkdirs()) {
throw new IOException("无法创建文件夹 " + savePath);
}
}
// 开始侦听
public void start() {
new ListenThread().start();
}
// 网上抄来的,将字节转成 int。b 长度不得小于 4,且只会取前 4 位。
public static int b2i(byte[] b) {
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += (b[i] & 0x000000FF) << shift;
}
return value;
}
/**
* 侦听线程
*/
private class ListenThread extends Thread {
@Override
public void run() {
try {
ServerSocket server = new ServerSocket(listenPort);
// 开始循环
while (true) {
Socket socket = server.accept();
new HandleThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 读取流并保存文件的线程
*/
private class HandleThread extends Thread {
private Socket socket;
private HandleThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
readAndSave(is);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
} catch (IOException e) {
// nothing to do
}
}
}
// 从流中读取内容并保存
private void readAndSave(InputStream is) throws IOException {
String filename = getFileName(is);
int file_len = readInteger(is);
System.out.println("接收文件:" + filename + ",长度:" + file_len);
readAndSave0(is, savePath + filename, file_len);
System.out.println("文件保存成功(" + file_len + "字节)。");
}
private void readAndSave0(InputStream is, String path, int file_len) throws IOException {
FileOutputStream os = getFileOS(path);
readAndWrite(is, os, file_len);
os.close();
}
// 边读边写,直到读取 size 个字节
private void readAndWrite(InputStream is, FileOutputStream os, int size) throws IOException {
byte[] buffer = new byte[4096];
int count = 0;
while (count < size) {
int n = is.read(buffer);
// 这里没有考虑 n = -1 的情况
os.write(buffer, 0, n);
count += n;
}
}
// 读取文件名
private String getFileName(InputStream is) throws IOException {
int name_len = readInteger(is);
byte[] result = new byte[name_len];
is.read(result);
return new String(result);
}
// 读取一个数字
private int readInteger(InputStream is) throws IOException {
byte[] bytes = new byte[4];
is.read(bytes);
return b2i(bytes);
}
// 创建文件并返回输出流
private FileOutputStream getFileOS(String path) throws IOException {
File file = new File(path);
if (!file.exists()) {
file.createNewFile();
}
return new FileOutputStream(file);
}
}
}
- /**
- * 发送端
- */
- class Client {
- // 网上抄来的,将 int 转成字节
- public static byte[] i2b(int i) {
- return new byte[]{
- (byte) ((i >> 24) & 0xFF),
- (byte) ((i >> 16) & 0xFF),
- (byte) ((i >> 8) & 0xFF),
- (byte) (i & 0xFF)
- };
- }
- /**
- * 发送文件。文件大小不能大于 {@link Integer#MAX_VALUE}
- *
- * @param hostname 接收端主机名或 IP 地址
- * @param port 接收端端口号
- * @param filepath 文件路径
- *
- * @throws IOException 如果读取文件或发送失败
- */
- public void sendFile(String hostname, int port, String filepath) throws IOException {
- File file = new File(filepath);
- FileInputStream is = new FileInputStream(filepath);
- Socket socket = new Socket(hostname, port);
- OutputStream os = socket.getOutputStream();
- try {
- int length = (int) file.length();
- System.out.println("发送文件:" + file.getName() + ",长度:" + length);
- // 发送文件名和文件内容
- writeFileName(file, os);
- writeFileContent(is, os, length);
- } finally {
- os.close();
- is.close();
- }
- }
- // 输出文件内容
- private void writeFileContent(InputStream is, OutputStream os, int length) throws IOException {
- // 输出文件长度
- os.write(i2b(length));
- // 输出文件内容
- byte[] buffer = new byte[4096];
- int size;
- while ((size = is.read(buffer)) != -1) {
- os.write(buffer, 0, size);
- }
- }
- // 输出文件名
- private void writeFileName(File file, OutputStream os) throws IOException {
- byte[] fn_bytes = file.getName().getBytes();
- os.write(i2b(fn_bytes.length)); // 输出文件名长度
- os.write(fn_bytes); // 输出文件名
- }
- }
/**
* 发送端
*/
class Client {
// 网上抄来的,将 int 转成字节
public static byte[] i2b(int i) {
return new byte[]{
(byte) ((i >> 24) & 0xFF),
(byte) ((i >> 16) & 0xFF),
(byte) ((i >> 8) & 0xFF),
(byte) (i & 0xFF)
};
}
/**
* 发送文件。文件大小不能大于 {@link Integer#MAX_VALUE}
*
* @param hostname 接收端主机名或 IP 地址
* @param port 接收端端口号
* @param filepath 文件路径
*
* @throws IOException 如果读取文件或发送失败
*/
public void sendFile(String hostname, int port, String filepath) throws IOException {
File file = new File(filepath);
FileInputStream is = new FileInputStream(filepath);
Socket socket = new Socket(hostname, port);
OutputStream os = socket.getOutputStream();
try {
int length = (int) file.length();
System.out.println("发送文件:" + file.getName() + ",长度:" + length);
// 发送文件名和文件内容
writeFileName(file, os);
writeFileContent(is, os, length);
} finally {
os.close();
is.close();
}
}
// 输出文件内容
private void writeFileContent(InputStream is, OutputStream os, int length) throws IOException {
// 输出文件长度
os.write(i2b(length));
// 输出文件内容
byte[] buffer = new byte[4096];
int size;
while ((size = is.read(buffer)) != -1) {
os.write(buffer, 0, size);
}
}
// 输出文件名
private void writeFileName(File file, OutputStream os) throws IOException {
byte[] fn_bytes = file.getName().getBytes();
os.write(i2b(fn_bytes.length)); // 输出文件名长度
os.write(fn_bytes); // 输出文件名
}
}
看起来很复杂的样子,对于一个刚刚接触的人来说却是不怎么容易理解,那么这是一个怎么样的逻辑的,我们分析一下就会变得比较简单了;
首先来讲这个例子是说一个完整的文件传输包括文件大小,文件名称,文件内容。显然对于我们来说要一个个得来。对于文件大小文件名称,我们完全可以用一个固定的常量来代替,这样就大大简化了代码的复杂度,最终也就变成了如何传送文件内容!
1,读取文件内容,
2,发送内容,
说起来好简单的样子但是要怎么做呢?
- FileInputStream is = new FileInputStream(this.FilePath);
- byte Buffer[] = new byte[1024 * 8];
- while ((size = is.read(buffer)) != -1) {
- //System.out.println(size + " ");
- outputstream.write(buffer, 0, size);
- }
FileInputStream is = new FileInputStream(this.FilePath);
byte Buffer[] = new byte[1024 * 8];
while ((size = is.read(buffer)) != -1) {
//System.out.println(size + " ");
outputstream.write(buffer, 0, size);
}
客户端怎么接收呢?
- InputStream inputStream = socket.getInputStream();
InputStream inputStream = socket.getInputStream();
- int Size;
int Size;
- byte Buffer[] = new byte[1024 * 8];
- while ((Size = inputStream.read(Buffer)) != -1) {
- System.out.print(Size + " ");
byte Buffer[] = new byte[1024 * 8];
while ((Size = inputStream.read(Buffer)) != -1) {
System.out.print(Size + " ");
- system.out.print(new String11(b<SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">uffer</SPAN><SPAN style="FONT-FAMILY: Arial, Helvetica, sans-serif">));//此处文档显示有问题所以加了个11,源码需要去掉!</SPAN>
system.out.print(new String11(b<span style="FONT-FAMILY: Arial, Helvetica, sans-serif">uffer</span><span style="FONT-FAMILY: Arial, Helvetica, sans-serif">));//此处文档显示有问题所以加了个11,源码需要去掉!</span>
- }
}
这样看起来是不是就没那么复杂了呢 ,其实很多东西动手自己做,你会发现是如此的简单!