socket编程(二):TCP传文本文件、传二进制文件

承上篇文章:socket编程:TCP、UDP传字符串

传输中关于输入输出流和字符格式的问题上一篇大多有说过。

代码有些细节部分可能没有注意到,比如已知字节数可以判断循环终止然后又设了行数,对于流的初始化不够简洁等。主要是把两部分代码放在一起完成了,有些代码是一开始没有设计的后来填补上的,可能有重复,或者有效率更高的方法,大家自行斟酌。

一、利用TCP传文本文件

1、代码

实现client端先发送目录路径,server端返回目录内容,client端进行选择后server发送选择的文件的功能,代码如下,略去导入部分:

​
​
客户端:
public class TCPfileclient {
	public static void main(String args[]) throws IOException {
	 String dirurl;//目录路径
	 String dircontent;//文件夹内容
	 String filename;//文件名
	 String saveurl="C:\\Users\\Lenovo\\Desktop";//保存路径
	 Socket clientSocket=new Socket("localhost",10001);
	 BufferedReader infromUser=new BufferedReader(new InputStreamReader(System.in));//定义字符输入流对象,从键盘读入数据
	 DataOutputStream outToServer=new DataOutputStream(clientSocket.getOutputStream());//给socket赋予输出流
	 BufferedReader infromServer=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));//给socket赋予输入流
	 
	 dirurl=infromUser.readLine()+'\n';//读入目录路径
	 outToServer.write(dirurl.getBytes());//发送给server
	 outToServer.flush();//传输时要用flush(),把数据推出去,不然可能在缓存中没有传过去
	 dircontent=infromServer.readLine();//获得目录	
	 while(dircontent.equals("is not a folder")) {//不是文件夹重输
		 System.out.println("不是文件夹,请重新选择:");
		 dirurl=infromUser.readLine()+'\n';//读入目录路径
		 outToServer.write(dirurl.getBytes());//发送给server
		 outToServer.flush();
		 dircontent=infromServer.readLine();//获得目录	
	 }
	 System.out.println("文件夹目录为:"+dircontent);//显示目录
	 
	 
	 System.out.println("请选择文件:");
	 filename=infromUser.readLine()+'\n';//控制台选择文件
	 outToServer.write(filename.getBytes());//传递文件名给server
	 outToServer.flush();
	 
	 String fileName=infromServer.readLine();
	while(fileName.equals("404")) {//未找到文件重输
		System.out.println("404 Not Found");
		System.out.println("请选择文件:");
		filename=infromUser.readLine()+'\n';//控制台选择文件
		outToServer.write(filename.getBytes());//传递文件名给server
		outToServer.flush();
		fileName=infromServer.readLine();
	}
	
	fileName = "fromserver"+fileName;//获取文件名 
	File file=new File(saveurl+File.separatorChar+fileName);//创建文件对象
	long size=Integer.parseInt(infromServer.readLine());//获取文件字节数
	System.out.println("file。。。。。。。。。。。。。。"+file);
	System.out.println("fileName。。。。。。。。。。。。。。"+fileName);
	System.out.println("size。。。。。。。。。。。。。。"+size);
	System.out.println("======== 开始接收文件 ========");
   //以下为传输文本文件的代码
	BufferedWriter fileWritter = new BufferedWriter(new FileWriter(file));
	int count=infromServer.read();//获取行数,用于判断循环次数
	String str;
	while(count--!=0) {
		str=infromServer.readLine();
		System.out.println(str);
		str+='\n';
		fileWritter.write(str); 
	}
    fileWritter.close();
	//对上部分进行替换可传输其他文件
	System.out.println("======== 文件接收成功 ========");
	clientSocket.close();
	}
}






服务端:
public class TCPfileserver {
	public static void main(String args[]) throws IOException {
		String dirurl;
		String filename;
		@SuppressWarnings("resource")
		ServerSocket server=new ServerSocket(10001);
		while(true) {
			Socket connectionSocket=server.accept();
			BufferedReader requestfromClient=new BufferedReader(new InputStreamReader(connectionSocket.getInputStream()));//从输入流获取字节流
			DataOutputStream ToClient=new DataOutputStream(connectionSocket.getOutputStream());//设置输出流
			dirurl=requestfromClient.readLine();//获取请求文件夹路径
			System.out.println("请求文件夹为:"+dirurl);//显示路径
			
			File folder = new File(dirurl);
			String trans="is not a folder\n";
			while(!folder.isDirectory()) {//不是文件夹,给予提示,重新获取
				ToClient.write(trans.getBytes());
				ToClient.flush();
				folder = new File(dirurl);
			}
			
				String [] nameList = folder.list();
				String totalname = null;
				for(int i=0;i

2、实验效果

client端实验效果如下:

输入目录路径,返回目录,输入文件名,进行传输,打印相关信息,提示开始,显示传输字符,提示完成。出现中文乱码问题是从BufferedReader中取中文出现的问题,不是传输问题。可以用以下代码解决:

InputStreamReader isr = new InputStreamReader(new FileInputStream(file), "UTF-8");        

BufferedReader in = new BufferedReader(isr); 

socket编程(二):TCP传文本文件、传二进制文件_第1张图片

Server端实验效果如下:

socket编程(二):TCP传文本文件、传二进制文件_第2张图片

 

fromserverwelcome.txt文件打开显示正常,显示结果如下:

socket编程(二):TCP传文本文件、传二进制文件_第3张图片

二、编写程序可以传输任意文件 

1、代码

客户端:
对传文本文档中客户端注释部分代码修改为以下代码:
@SuppressWarnings("resource")
	FileOutputStream fos=new FileOutputStream(file);
	 DataInputStream dis=new DataInputStream(clientSocket.getInputStream());  
	byte[] bytes = new byte[1024];  
    int length = 0; 
    while((size-=length)>0) {  
    	length = dis.read(bytes, 0, bytes.length);
        fos.write(bytes, 0, length);  
        fos.flush();  
        System.out.println(size);
    }





服务端:
对传文本文档中服务端注释部分代码修改为以下代码:
@SuppressWarnings("resource")
	FileInputStream fis=new FileInputStream(file);
	byte[] bytes = new byte[1024];  
	int length = 0;  
	while((length = fis.read(bytes, 0, bytes.length)) != -1) {  
	   ToClient.write(bytes, 0, length);  
	   ToClient.flush(); 
}

2、实验效果

客户端显示结果为:

文件传输中显示的中间数列是剩余字节百分比。

socket编程(二):TCP传文本文件、传二进制文件_第4张图片

服务端显示结果为:

socket编程(二):TCP传文本文件、传二进制文件_第5张图片

传输文档打开后为:

socket编程(二):TCP传文本文件、传二进制文件_第6张图片

其中遇到了问题:

其他人使用循环遍历读取字节流时循环条件都写成了:

​
​
  while((length = dis.read(bytes, 0, bytes.length)) != -1) {//有的人这里写成判断readLine()是否是null  
                    fos.write(bytes, 0, length);  
                    fos.flush();  
                }  

​

​

如这篇文章: Java Socket实现文件传输

我运行时遇到了接收端接收完后还在一直等待的情况,推测是发送端发完数据后就没有再发,接收端也不会读取到结束标志,以为后面还有就在持续等待。所以我用的都是字节数或行数判断循环是否该终止。但是其他人都运行出来了也不知道是怎么回事,期待有人解惑。

你可能感兴趣的:(socket编程(二):TCP传文本文件、传二进制文件)