我刚做了个Socket聊天程序,现在还想做一个发送文件的功能

a2506560872 2012-03-02 05:52:18
rt,网上找了一些代码,但是只能发送一个文件,要么就只能关闭socket。但是这样都不完美。所以我想做一个可以想发送多少就发送多少的程序。哪个高手能告诉我该怎么做啊。有实例代码更好。234440967@qq.com(这是我的邮箱)
...全文
303 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
a2506560872 2012-03-05
  • 打赏
  • 举报
回复
嗯。成功了,谢谢各位大哥。我再把我的代码改进改进。争取做到最好。尤其是谢谢ldh911和dntg007我要努力。。。。。。
桃园闲人 2012-03-03
  • 打赏
  • 举报
回复
一个和多个没多大区别吧,你把文件放到多个byte数组中,然后依次传送就可以了,最好是封装一个类包含(文件属性信息,文件byte数据,,)
a2506560872 2012-03-03
  • 打赏
  • 举报
回复
---------这是客户端代码
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;
}
a2506560872 2012-03-03
  • 打赏
  • 举报
回复
package fileTransfer;

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 = 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();
}
}
//这是我写的。客户端该怎么循环啊。
dntg007 2012-03-03
  • 打赏
  • 举报
回复
其实这相当于你自己要定义一份协议。这边发送数据是什么结构,那边接受数据要能对应上。关于发送文件的结构,2楼已经说的很完善了。主要还是收发两边的控制,发数据,没啥说的,按照自己定义的结构逐个发送就行。收数据那边要对应上。比如说,默认第一次接收只接收一个字节的数据(二楼写的用了4个字节:发送文件标识(4byte)看你具体有多少种命令,如果觉得以后扩展功能可能很大,就多留点字节)。可以byte cmdTypeByte[] = new byte[1];然后去读出第一个字节,根据这个值来判断对方是在发送聊天内容还是在发送文件。如果是发送文件那么先再读两个8个字节,前4个字节恢复成int数值,确定文件名长度,然后再去读指定长度个字节,组合成字符串,就是你要保存的文件名。然后同理再读数据。
如果你想做的完善些,客户端就不要着急发实际文件数据。服务端接收发送文件请求后,可以弹出个选择框,可以选择保存的路径或者说不接收数据等等。
再完善些如果发送大文件,两边都可以加入中途停止发送功能。如果是发送文件一方停止,接收方正在接收数据,无法获得发送方已经停止发送的消息(因为没接收完文件数据,接收的所有数据都作为文件数据处理)。这个时候最好在开一个端口。有点像硬件的处理,一个端口专门做命令处理,一个端口专门做数据处理。
做的完善些,中途停止后再重新发送文件,如果接收文件方保存的路径不变。原则上也可以做续传处理。将传了一半的文件大小发给发送方,让他直接把这个大小后面的数据发过来。接收方续写文件就行了。

至于说多个文件传送,循环处理就行了。挺多就是修正下接收方是询问还是默认直接执行罢了。
MiceRice 2012-03-03
  • 打赏
  • 举报
回复
【客户端代码】


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();
}
}
MiceRice 2012-03-03
  • 打赏
  • 举报
回复
看你的代码压力很大,我写了个你参考下吧。

但是要特别说明下:
不支持多级目录处理!因为多级目录处理还涉及到要通知客户端关于子目录创建的问题。
不支持自动删除文件!这个涉及到要跟客户端文件做比对。

服务端代码:

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();
}
}
MiceRice 2012-03-02
  • 打赏
  • 举报
回复
哦,看你的程序是打算 服务器端给客户端发送文件,但在逻辑切分上有些不合理。

先假定你只能给一个客户端传送文件吧。

这个函数:void start();(先去掉while true)
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中得到了输出流,在用完之前就千万别关闭它。
a2506560872 2012-03-02
  • 打赏
  • 举报
回复
我逻辑混乱了,想不到有什么方法可以连续传输多个文件。
以下是服务器端代码
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();
}
}
a2506560872 2012-03-02
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 ldh911 的回复:]

没看出来你觉得主要问题是啥?

一般来说,只需要发送文件前,告知目标方,比如:发送文件标识(4byte) + 文件名长度(4byte) + 文件长度(4byte) + 文件名 + 文件内容。

目标方就能够处理了。
Java的缺憾主要是因为没有C++里面的“结构”,所以对于这种定长信息的处理缺乏优势。
但也不是啥很大问题才对。
[/Quote] 主要问题是怎么可以使socket连续传输多个文件。
MiceRice 2012-03-02
  • 打赏
  • 举报
回复
没看出来你觉得主要问题是啥?

一般来说,只需要发送文件前,告知目标方,比如:发送文件标识(4byte) + 文件名长度(4byte) + 文件长度(4byte) + 文件名 + 文件内容。

目标方就能够处理了。
Java的缺憾主要是因为没有C++里面的“结构”,所以对于这种定长信息的处理缺乏优势。
但也不是啥很大问题才对。

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧