FileInputStream in = new FileInputStream(f2[i]); System.out.println(f2[i].getPath()); System.out.println(f2[i].getName()); DataInputStream dis = new DataInputStream(new BufferedInputStream(s.getInputStream())); dis.readByte(); DataInputStream fis = new DataInputStream(new BufferedInputStream(in)); DataOutputStream ps = new DataOutputStream(s.getOutputStream()); //将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In Java 4th里有现成的代码。
ps.writeUTF(f3.getName()); ps.flush(); ps.writeLong((long) f3.length()); ps.flush(); int bufferSize = 8192; byte[] buf = new byte[bufferSize]; while (true) { int read = 0; if (fis != null) { read = fis.read(buf); } if (read == -1) { break; } ps.write(buf, 0, read); } ps.flush(); fis.close(); } } } public static void main(String arg[]) { new server1().start(); } }
Java的缺憾主要是因为没有C++里面的“结构”,所以对于这种定长信息的处理缺乏优势。
但也不是啥很大问题才对。
以下是服务器端代码
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class server1 {
int port = 8821; void start() {
Socket s = null;
try {
ServerSocket ss = new ServerSocket(port);
while (true) {
// 选择进行传输的文件
String filePath = "D:\\BackFolder";
File fi = new File(filePath); System.out.println("文件长度:" + (int) fi.length());
File [] f2=fi.listFiles();
// public Socket accept() throws
// IOException侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
s = ss.accept();
System.out.println("建立socket链接");
server(f2,s);
System.out.println("文件传输完成");
s.close();
} } catch (Exception e) {
e.printStackTrace();
}
}
public void server(File [] f2,Socket s) throws IOException
{
for(int i=0;i<f2.length;i++){
File f3=f2[i];
if(f3.isDirectory()==true)
{
File [] f4=f3.listFiles();
server(f4,s);
}else{
FileInputStream in = new FileInputStream(f2[i]);
System.out.println(f2[i].getPath());
System.out.println(f2[i].getName());
DataInputStream dis = new DataInputStream(new BufferedInputStream(s.getInputStream()));
dis.readByte();
DataInputStream fis = new DataInputStream(new BufferedInputStream(in));
DataOutputStream ps = new DataOutputStream(s.getOutputStream());
//将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In Java 4th里有现成的代码。
ps.writeUTF(f3.getName());
ps.flush();
ps.writeLong((long) f3.length());
ps.flush(); int bufferSize = 8192;
byte[] buf = new byte[bufferSize]; while (true) {
int read = 0;
if (fis != null) {
read = fis.read(buf);
} if (read == -1) {
break;
}
ps.write(buf, 0, read);
}
ps.flush();
fis.close();
}
}
}
public static void main(String arg[]) {
new server1().start();
}
}
1、等待客户端接入,也就是:ss.accept();
2、打开发送流:DataOutputStream ps = new DataOutputStream(s.getOutputStream());
3、获取文件列表,也就是:File [] f2=fi.listFiles();
4、循环f2;
5、循环中调用sendfile( f2[i], ps);
6、关闭ps(如果你还想再干其它的事情的话,那么这个连接必须用不关闭)。然后是:void sendfile(File f, DataOutputStream ps);
1、读取方式打开文件;
2、获取文件大小和文件名;
3、将文件大小和文件名大小,写入ps;
4、将文件名写入ps;
5、循环将整个文件内容写入ps;
6、return。关键在你一旦从Socket中得到了输出流,在用完之前就千万别关闭它。
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class server1 {
int port = 8823; void start() {
Socket s = null;
try {
ServerSocket ss = new ServerSocket(port);
// 选择进行传输的文件
String filePath = "D:\\BO";
File fi = new File(filePath); System.out.println("文件长度:" + (int) fi.length());
File[] f2 = fi.listFiles();
// public Socket accept() throws
// IOException侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
s = ss.accept();
System.out.println("建立socket链接");
// DataInputStream dis = new DataInputStream(new
// BufferedInputStream(s.getInputStream()));
// DataInputStream fis = new DataInputStream(new
// BufferedInputStream(in));
DataOutputStream ps = new DataOutputStream(s.getOutputStream());
DataInputStream dis = new DataInputStream(new BufferedInputStream(s
.getInputStream()));
for (int i = 0; i < f2.length; i++) {
File f3 = f2[i];
if (f3.isDirectory() == true) {
// //File [] f4=f3.listFiles();
// sendfile(f4,ps);
} else { // FileInputStream in = new FileInputStream(f2[i]);
System.out.println(f2[i].getPath());
System.out.println(f2[i].getName());
sendfile(f2[i], ps,dis);
}
}
// dis.readByte();
System.out.println("文件传输完成");
s.close(); } catch (Exception e) {
e.printStackTrace();
}
} public void sendfile(File f2, DataOutputStream ps,DataInputStream dis ) throws IOException { FileInputStream in = new FileInputStream(f2);
System.out.println("??????????");
dis.readByte();
DataInputStream fis = new DataInputStream(new BufferedInputStream(in));
// 将文件名及长度传给客户端。这里要真正适用所有平台,例如中文名的处理,还需要加工,具体可以参见Think In Java
// 4th里有现成的代码。
ps.writeUTF(f2.getName());
ps.flush();
ps.writeLong((long) f2.length());
ps.flush(); int bufferSize = 8192;
byte[] buf = new byte[bufferSize]; while (true) {
int read = 0;
if (fis != null) {
read = fis.read(buf);
} if (read == -1) {
break;
}
ps.write(buf, 0, read);
}
ps.flush();
fis.close(); } public static void main(String arg[]) {
new server1().start();
}
}
//这是我写的。客户端该怎么循环啊。
if (cs == null)
return;
DataInputStream inputStream = null;
try {
inputStream = cs.getMessageStream();
} catch (Exception e) {
System.out.print("接收消息缓存错误");
return;
} try {
// 本地保存路径,文件名会自动从服务器端继承而来。
String savePath = "E:\\";
int bufferSize = 0000;
byte[] buf = new byte[bufferSize];
int passedlen = 0;
long len = 0;
long lastPer = 0;
long thisPer = 0;
String fileName = "";
fileName = inputStream.readUTF();
savePath += fileName;
DataOutputStream fileOut = new DataOutputStream(
new BufferedOutputStream(new BufferedOutputStream(
new FileOutputStream(savePath))));
len = inputStream.readLong();
System.out.println("文件名:" + fileName + "\t文件的长度为:" + len/1024/1024 + "M");
System.out.println("开始接收文件..." + "");
System.out.print("<");
int read = 0; while (true) {
if (inputStream != null) {
read = inputStream.read(buf);
}
passedlen += read;
if (read == -1) {
break;
}
// 下面进度条本为图形界面的prograssBar做的,这里如果是打文件,
// 可能会重复打印出一些相同的百分比
thisPer = passedlen * 100 / len;
if(thisPer > lastPer)
{
lastPer = thisPer;
System.out.print("=" + thisPer);
}
fileOut.write(buf, 0, read);
System.out.println(">");
System.out.println("接收完成,文件存为" + savePath + "");
//fileOut.flush();
}
fileOut.close();
} catch (Exception e) {
System.out.println("接收消息错误" + "");
return;
}
不支持多级目录处理!因为多级目录处理还涉及到要通知客户端关于子目录创建的问题。
不支持自动删除文件!这个涉及到要跟客户端文件做比对。服务端代码:package io;import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.net.ServerSocket;
import java.net.Socket;/**
* 文件传输,服务端,负责将制定目录下的文件无条件发给FileClient
*/
public class FileServer {
public static final int PORT = 8823; public static final String DIR_PATH = "D:\\BO\\server"; public static File rootdir = new File(DIR_PATH); byte[] buffer = new byte[16 * 1024]; // 16K缓存大小 /**
* @param msg 输出日志
*/
private void log(Object msg) {
System.out.println(msg);
} /**
* 服务启动函数
* @throws Exception 懒得写捕获异常及处理了
*/
void start() throws Exception {
ServerSocket serverSocket;
Socket socket;
while (true) {
serverSocket = new ServerSocket(PORT);
log("服务端就绪,等待客户端连接"); // 侦听并接受到此套接字的连接。此方法在进行连接之前一直阻塞。
socket = serverSocket.accept();
log("有客户端连接上来了,已建立Socket链接"); // 准备好输出(因为不关心客户端发什么信息过来,所以输入流也不管它了)
DataOutputStream socketOut = new DataOutputStream(socket.getOutputStream()); // 借助递归处理所有的目录下的文件
log("准备传输所有文件");
sendAllFile(rootdir, socketOut);
log("文件传输完成"); // 发送结束标志
socketOut.writeLong(-1); serverSocket.close();
}
} /**
* 借助递归处理所有的目录下的文件
* @param fileOrDir 文件或目录
* @param socketOut 面向FileClient的输出流
*/
private void sendAllFile(File fileOrDir, DataOutputStream socketOut) throws Exception {
if (fileOrDir.isDirectory()) {
File[] fs = fileOrDir.listFiles();
log("找到目录[" + fileOrDir.getName() + "],其下子目录及文件数:" + fs.length);
for (int i = 0; i < fs.length; i++) {
sendAllFile(fs[i], socketOut);
}
} else {
log("准备传输文件:" + fileOrDir.getName());
writeOutTheFile(fileOrDir, socketOut);
}
} /**
* 文件发送
* @param file 文件
* @param socketOut 面向FileClient的输出流
*/
public void writeOutTheFile(File file, DataOutputStream socketOut) throws Exception { // 先准备好文件名和总长度信息
String filename = file.getName();
byte[] bytename = filename.getBytes();
long fileSize = file.length();
int nameSize = bytename.length; // 1、发送长度信息
log("发送长度信息:" + fileSize + "\t\t" + filename + ":" + nameSize);
socketOut.writeLong(fileSize);
socketOut.writeInt(nameSize); // 2、发送文件名
socketOut.write(bytename); // 3、发送文件内容
FileInputStream in = new FileInputStream(file);
int size; // 记录每次读取大小
try {
while ((size = in.read(buffer)) > 0) {
socketOut.write(buffer, 0, size);
}
} finally {
in.close();
}
socketOut.flush(); // 4、如果高兴的话,可以再发个MD5文件校验码,让FileClient去检查下所接收数据是否正确。
} public static void main(String arg[]) throws Exception {
new FileServer().start();
}
}
package io;import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.Socket;/**
* 文件传输,客户端,负责连接FileServer并将其所传送过来的文件无条件记录下来
*/
public class FileClient {
public static final String SERVER = "localhost"; public static final int PORT = 8823; public static final String DIR_PATH = "D:\\BO\\client"; public static File rootdir = new File(DIR_PATH); byte[] buffer = new byte[16 * 1024]; // 16K缓存大小 /**
* @param msg 输出日志
*/
private void log(Object msg) {
System.out.println(msg);
} void start() throws Exception {
Socket socket = new Socket(SERVER, PORT);
try {
log("成功连接服务器端,准备接收文件");
DataInputStream socketIn = new DataInputStream(new BufferedInputStream(socket.getInputStream())); while (readInTheFile(rootdir, socketIn));
} finally {
socket.close();
}
} boolean readInTheFile(File dir, DataInputStream socketIn) throws Exception {
// 获取头部信息:文件大小、文件名长度、文件名
long filesize = socketIn.readLong();
if (filesize < 0) {
log("服务器端文件发送已经结束");
return false;
}
int namesize = socketIn.readInt();
socketIn.read(buffer, 0, namesize);
String filename = new String(buffer, 0, namesize);
log("得到文件信息,文件大小:" + filesize + "\t文件名长度:" + namesize + "\t" + filename); // 准备本地写入文件
File file = new File(dir, filename);
FileOutputStream out = new FileOutputStream(file); // 从服务器端获取文件内容,并写入本地
int size; // 记录每次读取大小
try {
while (true) {
size = (int) ((buffer.length < filesize) ? buffer.length : filesize);
size = socketIn.read(buffer, 0, size);
if (size <= 0)
break;
out.write(buffer, 0, size);
filesize -= size;
}
} finally {
out.close();
}
return true;
} public static void main(String[] args) throws Exception {
new FileClient().start();
}
}
如果你想做的完善些,客户端就不要着急发实际文件数据。服务端接收发送文件请求后,可以弹出个选择框,可以选择保存的路径或者说不接收数据等等。
再完善些如果发送大文件,两边都可以加入中途停止发送功能。如果是发送文件一方停止,接收方正在接收数据,无法获得发送方已经停止发送的消息(因为没接收完文件数据,接收的所有数据都作为文件数据处理)。这个时候最好在开一个端口。有点像硬件的处理,一个端口专门做命令处理,一个端口专门做数据处理。
做的完善些,中途停止后再重新发送文件,如果接收文件方保存的路径不变。原则上也可以做续传处理。将传了一半的文件大小发给发送方,让他直接把这个大小后面的数据发过来。接收方续写文件就行了。至于说多个文件传送,循环处理就行了。挺多就是修正下接收方是询问还是默认直接执行罢了。