Java Client/Server 上传文件到服务器与保存文件到本地

Posted 一身千寻瀑

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Client/Server 上传文件到服务器与保存文件到本地相关的知识,希望对你有一定的参考价值。

新年第一章,祝大家新年快乐。

-----------------------------------------------------------------------

这个是我们的Java期末考试题,圣诞节的考试庆典。考试时长三个小时,晚上19:00-22:00。

包括考试要求到最后的源程序,都会搬到这里。

三个小时还是比较紧张的,虽然经过一学期学习,还是会有BUG以及其他缺点。

这次是基于JavaSocket使Client与Server通信,以文本文档的形式上传一个查询结果到服务器的功能。

查询是基于Sql Server中的一个很简易的数据库中的一个简单表。

-----------------------------------------------------------------------

出现的问题:

需要用到JDBC驱动,当时导出的jar文件怎么都不能连到数据库,添加external library的时候有些问题,再次加载项目导入的jdbc就没有了。

这应该是一点没有完成考试要求的地方,毕竟只有三个小时,时间上还是非常紧张的。

-----------------------------------------------------------------------

一点反思:

1.以后做项目的时候,会不会因为赶工期而使项目很多bug或者不安全的地方被忽略,导致项目质量的低下,进而加重后期维护系统的难度?

2.jdbc驱动问题导致的导出jar文件不能连接数据库是什么问题?考后询问老师只得到项目文件.classpath有问题的反馈。

-----------------------------------------------------------------------

下面贴考试内容:


这是第一题,分值20分。

考查点其实就是小黑窗下java文件的编译与运行,加上了package,需多使用“ -d . ”而已。

小黑窗的反馈结果直接贴在word里,这20分应该来说还是很容易的。

有一点需要说的是,其实第一遍调试我是出错误的,因为直接把代码贴到txt里也没有修改。

激动地差点举手找监考,然而提示里都说了需要修改。导入one.MyTest就好了。

五分钟,第一题20分送到手。

剩下的近三小时就是第二题的Java项目了。

-------------------------------------------------------分--割--线-------------------------------------------------------

二:综合应用题(80分)

请在DBMS中按下面的要求定义表结构。(DBMS任选,建议:SQLServer版本与实验室一致

数据库结构(注意:建立的数据库名称、结构等必须和下面的描述完全一致):

数据库名称:examdb

包括一个表:

课程信息表,表名称:mycourse

属性

类型

长度

含义

是否空值

cno

varchar

7

课程号

cname

varchar

20

课程名

cred

float

(3,1)

课程学分

iscom

varchar

2

是否选修

tech

varchar

10

授课教师

注意:(数据库设计的运用!)

2使用Java  Swing组件开发一个图形界面,界面布局及控件如下图所示

实现具体要求与分值分配:

1 请严格按照Java的代码规范进行代码组织15%

例如: 类名、包名、方法名、接口等的命名规范,注释、代码格式规范等。

注意:主项目(project)名称为学号,一级包名为姓名的拼音

2 请选择合适的布局、组件、容器、事件、事件监听器等实现题目要求的功能25%,其中:

GUI组件选择与界面实现(10%)

面向对象的结构及代码的一些优化处理(15%),    包括:类结构设计、功能优化设计(10%),异常处理、错误提示界面(5%)。

3 功能实现部分35%

功能1,查询(15%:单击查询按钮,可以实现按照用户选择的“课程号”或者“课程名”与文本框输入的具体内容到数据库端进行查询,并将结果返回到窗口的组件中显示出来。

提示:注意提供中文的查询支持!

功能2,保存至文件(10%:获取窗口组件中显示得满足条件的记录,选择合适的IO API将其保存成文件形式。

文件名:(保存路径为项目文件夹或者使用图形化界面进行选择)

chaxunno.txt,(按照课程号查询的结果保存的文件)。

chaxunname.txt(按照课程名称查询的结果保存的文件)。

功能3,保存至服务器(10%:请将上述功能2中存储的两个文件上传到服务器上存储。(保存路径为项目文件夹或者使用图形化界面进行选择)

注意:此处服务器就是本机。

服务器端口号统一使用8993.

文件名分别是:chaxunnoser.txt、chaxunnameser.txt

4 将项目生成可执行的jar文件(5%

提交说明:

请将项目文件夹(若干)保存结果的文件(若干)可执行jar文件考试文件(包含第一题答案)并附带一个说明.txt (内容为:学号、姓名、联系方式;数据库连接URL中的用户名、密码、数据库产品名称等;以及自己认为有必要说明的其它问题),全部打包到自己学号命名的rar文件中,上传至ftp。

----------------------------------------------------------------------------------------------------------------------------------------------------

乍一看都是lecture和experiment上讲过练过的,思路很清晰,但是代码量多,任务重。

这是最后的上传的结果:


2014****文件夹中是client端的实现,myserver中是server端的实现,最后的查询结果在三个txt文件中,说明txt中是对项目的ReadMe。

生成的jar文件是服务器.jar和客户端.jar,打开服务器端才能上传txt文件。

sqljdbc42是jdbc驱动。

java题稿是我从word里的题目要求提炼,与项目无关。

最后全部打包成2014****.zip上交,考试完毕。

----------------------------------------------------------------------分--割--线------------------------------------------------------------------------

sql server


很简单的一个examdb,没什么可说的。

----------------------------------------------------------------------分--割--线------------------------------------------------------------------------

eclipse Java项目,分两个。



-------------------------

以下是源代码:

ps:以前自己写的小程序不爱加注释,这次不仅仅是给自己看,所以必要的地方添加了注释。

---------------

myserver


my.ser

MyServerSocket.java

package my.ser;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.JOptionPane;

public class MyServerSocket 
	
	ServerSocket ss = null;
	Socket s = null;
	InputStream in = null;
	FileOutputStream fos = null;
	
	public void recFile() 
		
		try 
			
			ss = new ServerSocket(8893);
			JOptionPane.showMessageDialog(null,"端口已打开","提示",JOptionPane.INFORMATION_MESSAGE);
			//System.out.println("Opening the port."); 
			//服务器8893端口打开,输出一个提示消息
			
			s = ss.accept();
			
			in = s.getInputStream(); 
			
			fos = new FileOutputStream(new File("c://test//server//chaxunser.txt")); //上传到服务器指定位置文件夹
			
			byte[] buf = new byte[1024];
			int len = 0;
			
			while((len = in.read(buf)) != -1) 
				
				fos.write(buf, 0, len);
				fos.flush();
				
			
			
		 catch (IOException e) 
			// TODO Auto-generated catch block
			JOptionPane.showMessageDialog(null,"未知错误","错误",JOptionPane.ERROR_MESSAGE);
		
		
		
	
	
	public void myclose() 

		try 
			
			if(fos!=null) 
				fos.close();
			
			if(in!=null) 
				in.close();
			
			if(s!=null) 
				s.close();
			
			if(ss!=null) 
				ss.close();
			
			
		 catch (IOException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		
		
	



my.test

MainTest.java

package my.test;

import my.ser.MyServerSocket;

public class MainTest 
	
	public static void main(String[] s) 
		//打开服务器
		
		new MyServerSocket().recFile();
		new MyServerSocket().myclose();
		
	



--------------------------------------------------------------------------------------

client端

2014****


ycx.cli

MyClientSocket.java

package ycx.cli;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import ycx.savefile.MyFile;

public class MyClientSocket 
	
	Socket s = null;
	FileInputStream fis = null;
	OutputStream out = null;
	
	public int sendFile(ArrayList<String> list,int cic)  
		//list是查询结果,cic代表按照课程号(cic=1)或课程名(cic=2)查询的标识
		
		try 
			
			s = new Socket("127.0.0.1",8893); //尝试连接目标服务器8893端口
			
			//将list的内容保存到本地项目文件,准备向服务器上传文件
			if(cic==0) 
				MyFile myfile = new MyFile();
				myfile.saveMyFile("img/chaxunno.txt",list);
				fis = new FileInputStream("img/chaxunno.txt");
			
				
			if(cic==1) 
				MyFile myfile = new MyFile();
				myfile.saveMyFile("img/chaxunname.txt",list);
				fis = new FileInputStream("img/chaxunname.txt");
			
			
			out = s.getOutputStream();
			
			byte[] buf = new byte[1024];
			int len = 0;
			
			while((len = fis.read(buf)) != -1) 
				
				out.write(buf, 0, len);
				out.flush();
				
			
			
			s.shutdownOutput();
			return 1;
			
		 catch (UnknownHostException e) 
			// TODO Auto-generated catch block
			JOptionPane.showMessageDialog(null,"未知主机错误","错误",JOptionPane.ERROR_MESSAGE);
			return 0;
		 catch (IOException e) 
			// TODO Auto-generated catch block
			JOptionPane.showMessageDialog(null,"发生错误:请先建立连接","错误",JOptionPane.ERROR_MESSAGE);
			return 0;
		
		
	
	
	public void myclose() 
		try 
			
			if(fis!=null) 
				fis.close();
			
			if(out!=null) 
				out.close();
			
			if(s!=null) 
				s.close();
			
			
		 catch (IOException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		
	



ycx.savefile

MyFile.java

package ycx.savefile;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.ArrayList;

public class MyFile 
	
	public void saveMyFile(String filePath, ArrayList<String> result) 
		//参数为filePath和result,实现将result的内容写到filePath指定路径的文件中。
		
        try 
        	
            File myFile = new File(filePath.toString());
            if(myFile.exists()) 
            	// 如果该文件存在,则删除原文件
            	myFile.delete();
            
            if (!myFile.exists())  
            	// 如果该文件不存在,则创建
                myFile.createNewFile();
            
            
            FileWriter resultFile = new FileWriter(myFile, true);
            PrintWriter myFileWrite = new PrintWriter(resultFile);
            myFileWrite.println("  课程号    课程名   学分  选修  授课教师");
            //不覆盖先前内容,并追加后续内容到文件里。每次追加在txt中都有[..Content..]标识。
            myFileWrite.println(result);
            resultFile.close();
            
         catch (Exception e) 
            e.printStackTrace();
        
        
	



ycx.gui

EnterWindow.java

package ycx.gui;

import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.WindowConstants;

import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Color;
import java.awt.Font;

public class EnterWindow 
	
	/**
	 * @wbp.parser.entryPoint
	 */
	public void showEnterWindow() 
		
		JFrame jf = new JFrame();
		jf.setTitle("\\u6B22\\u8FCE\\u754C\\u9762");
		
		JLayeredPane layeredPane = new JLayeredPane();
		jf.getContentPane().add(layeredPane, BorderLayout.CENTER);
		
		JLabel label = new JLabel("\\u6B22\\u8FCE\\u60A8\\u767B\\u9646\\u672C\\u7CFB\\u7EDF");
		label.setFont(new Font("宋体", Font.PLAIN, 13));
		label.setForeground(Color.BLACK);
		label.setBounds(185, 56, 132, 39);
		layeredPane.add(label);
		
		JButton button = new JButton("\\u8FDB\\u5165");
		button.addActionListener(new ActionListener() 
			
			public void actionPerformed(ActionEvent e) 
				
				jf.setVisible(false);
				jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
				
				MyWindow mw = new MyWindow();
				mw.showMyWindow();
				
			
			
		);
		button.setBounds(191, 126, 93, 23);
		layeredPane.add(button);
		
		jf.setVisible(true);
		jf.setSize(500,300);
		jf.setLocation(400,200);
		
	



MyWindow.java

package ycx.gui;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;

import ycx.cli.MyClientSocket;
import ycx.jtmodel.MyTableModel;
import ycx.savefile.MyFile;

public class MyWindow 
	
	private JTextField textField;
	
	Connection ct = null;
	Statement ps = null;
	ResultSet rs = null;
	
	ArrayList<String> list = new ArrayList<String>();
	int cic = 0;
	
	/**
	 * @wbp.parser.entryPoint
	 */
	public void showMyWindow() 
		
		JFrame jf = new JFrame();
		jf.setTitle("\\u64CD\\u4F5C\\u7A97\\u53E3");
		
		JLayeredPane layeredPane = new JLayeredPane();
		jf.getContentPane().add(layeredPane, BorderLayout.CENTER);
		
		JLabel label = new JLabel("\\u8BF7\\u8F93\\u5165\\uFF1A");
		label.setBounds(219, 25, 65, 15);
		layeredPane.add(label);
		
		JTable jt = new JTable(0,5);
		JScrollPane jspa = new JScrollPane(jt);
		jspa.setBounds(20, 66, 438, 124);
		layeredPane.add(jspa);
		
		JComboBox<String> comboBox = new JComboBox<String>();
		comboBox.setBounds(108, 22, 93, 21);
		comboBox.addItem("课程号");
		comboBox.addItem("课程名");
		layeredPane.add(comboBox);
		
		textField = new JTextField("在此输入查询内容");
		textField.setBounds(266, 22, 109, 21);
		layeredPane.add(textField);
		textField.setColumns(10);
		
		try 
			//连接Sql Server数据库
			
			Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
			ct = DriverManager.getConnection
					("jdbc:sqlserver://127.0.0.1:1433;DatabaseName=examdb","sa","");
			ps = ct.createStatement();
			
		 catch (ClassNotFoundException e2) 
			// TODO Auto-generated catch block
			e2.printStackTrace();
			JOptionPane.showMessageDialog(null,"连接数据库失败","错误",JOptionPane.ERROR_MESSAGE);
		 catch (SQLException e1) 
			// TODO Auto-generated catch block
			e1.printStackTrace();
			JOptionPane.showMessageDialog(null,"连接数据库失败","错误",JOptionPane.ERROR_MESSAGE);
		
		
		
		JButton button = new JButton("\\u67E5\\u8BE2");
		button.addActionListener(new ActionListener() 
			
			public void actionPerformed(ActionEvent e) 
				//当单击"查询"按钮时,响应该事件
				
				cic = comboBox.getSelectedIndex();
				String str = textField.getText().trim();
				
				try 
					
					if(cic==0)  //按课程号查询
						rs = ps.executeQuery("select * from mycourse where cno like '%" + str + "%'");
					
					else if(cic==1)  //按课程名查询
						rs = ps.executeQuery("select * from mycourse where cname like '%" + str + "%'");
					
					
					MyTableModel mtm = new MyTableModel(rs);
					jt.setModel(mtm);
					
					list.clear(); //每次查询时先清空list缓存区
					
					//将数据预缓存到list中,后续利用list上传到服务器或保存到本地
					list.add("\\r\\n");
					//通过JTable.getValueAt(int row,int column)方法使list得到查询得结果
					for(int i = 0; i < jt.getRowCount(); ++i) 
						
						if(i!=0)
							list.add("\\r\\n");
						for(int j = 0; j < jt.getColumnCount(); ++j) 
							list.add(String.valueOf(jt.getValueAt(i, j)));
						
						
					
					list.add("\\r\\n");

					if(rs.isAfterLast()==false)
						JOptionPane.showMessageDialog(null,"未能查询到学生的信息","错误",JOptionPane.ERROR_MESSAGE);
					
				 catch (SQLException e1) 
					// TODO Auto-generated catch block
					e1.printStackTrace();
					JOptionPane.showMessageDialog(null,"不正确的选择语句","错误",JOptionPane.ERROR_MESSAGE);
				
				
			
			
		);
		button.setBounds(385, 21, 73, 23);
		layeredPane.add(button);
		
		JButton button_1 = new JButton("\\u4FDD\\u5B58\\u5230\\u672C\\u5730");
		button_1.addActionListener(new ActionListener() 
			
			public void actionPerformed(ActionEvent e) 
				//当单击"保存到本地"按钮时,响应该事件
				
				if(jt.getRowCount()==0)  //若JTable为空
					JOptionPane.showMessageDialog(null,"请先查询信息","提示",JOptionPane.INFORMATION_MESSAGE);
				
				else  //若JTable不为空
					
					//发出确认消息
					int YesOrNo = JOptionPane.showConfirmDialog(null, "确定要保存到本地吗?", "提示", JOptionPane.INFORMATION_MESSAGE);
					if(YesOrNo==JOptionPane.YES_OPTION) 
						
						//再把list的内容保存到文件中
						if(cic==0)   //按照课程号查询的结果保存文件
							new MyFile().saveMyFile("chaxunno.txt",list);
							JOptionPane.showMessageDialog(null,"保存成功","提示",JOptionPane.INFORMATION_MESSAGE);
						
							
						if(cic==1)   //按照课程名称查询的结果保存文件
							new MyFile().saveMyFile("chaxunname.txt",list);
							JOptionPane.showMessageDialog(null,"保存成功","提示",JOptionPane.INFORMATION_MESSAGE);
									
						
					
					
				
				
			
			
		);
		button_1.setBounds(92, 211, 120, 23);
		layeredPane.add(button_1);
		
		JButton button_2 = new JButton("\\u4FDD\\u5B58\\u5230\\u670D\\u52A1\\u5668");
		button_2.addActionListener(new ActionListener() 
			
			public void actionPerformed(ActionEvent e) 
				//当单击"上传到服务器"按钮时,响应该事件
				
				if(jt.getRowCount()==0)  //若JTable为空
					JOptionPane.showMessageDialog(null,"请先查询信息","提示",JOptionPane.INFORMATION_MESSAGE);
				
				else  //若JTable不为空
					
					//发出确认消息
					int YesOrNo = JOptionPane.showConfirmDialog(null, "确定要上传到服务器吗?", "提示", JOptionPane.INFORMATION_MESSAGE);
					if(YesOrNo==JOptionPane.YES_OPTION) 
						
						int flag = 0; //用于接收上传是否成功的反馈,成功为1,失败为0
						
						//向服务器上传文件
						MyClientSocket mcs = new MyClientSocket();
						flag = mcs.sendFile(list,cic);;
						mcs.myclose();
						
						if(flag==1)
							JOptionPane.showMessageDialog(null,"上传成功","提示",JOptionPane.INFORMATION_MESSAGE);
						else
							JOptionPane.showMessageDialog(null,"上传失败","提示",JOptionPane.INFORMATION_MESSAGE);
						
					
					
				
				
			
			
		);
		button_2.setBounds(255, 211, 120, 23);
		layeredPane.add(button_2);
		
		JLabel label_1 = new JLabel("\\u9009\\u62E9\\u67E5\\u8BE2\\u6761\\u4EF6\\uFF1A");
		label_1.setBounds(20, 25, 99, 15);
		layeredPane.add(label_1);
		
		jf.setVisible(true);
		jf.setSize(500,300);
		jf.setLocation(400,200);
		
	


ycx.jtmodel

这里主要是为了设计一个JTable的模板,把查询结果显示在JTable中,比JTextArea好,更具美观性,最主要的是方便操作,想取哪个元素取哪个元素。

MyTableModel.java

package ycx.jtmodel;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.swing.table.AbstractTableModel;

@SuppressWarnings("serial")
public class MyTableModel extends AbstractTableModel 
	
	ResultSet rs = null;
	int rowcount;
	ArrayList<String[]> list = new ArrayList<String[]>();
	
	public MyTableModel(ResultSet rs) 
		
		this.rs = rs;
		
		try 
			
			while(rs.next()) 
				
				rowcount++;
				
				String[] line = new String[] 
						rs.getString(1),rs.getString(2),String.valueOf(rs.getFloat(3)),rs.getString(4),rs.getString(5)
				;
				list.add(line);
				
			
			
		 catch (SQLException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		
		
	

	@Override
	public int getRowCount() 
		// TODO Auto-generated method stub
		
		return rowcount;
		
	

	@Override
	public int getColumnCount() 
		// TODO Auto-generated method stub
		
		int colcount = 0;
		
		try 
			
			colcount = rs.getMetaData().getColumnCount();
			
		 catch (SQLException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		
		return colcount;
		
	

	@Override
	public Object getValueAt(int rowIndex, int columnIndex) 
		// TODO Auto-generated method stub
		
		return list.get(rowIndex)[columnIndex];
		
	
	
	public String getColumnName(int column) 
		
		/*String name = null;
		
		try 
			name = rs.getMetaData().getColumnName(column+1);
		 catch (SQLException e) 
			// TODO Auto-generated catch block
			e.printStackTrace();
		*/
		
		String[] colname = new String[]
			"课程号","课程名","课程学分","是否选修","授课教师"
		;
		return colname[column];
		
	



ycx.test

MainTest.java

package ycx.test;

import ycx.gui.EnterWindow;

public class MainTest 
	
	public static void main(String[] s) 
		
		EnterWindow ew = new EnterWindow();
		ew.showEnterWindow();
		
	



以上是所有代码。

--------------------------------------------------------分--割--线--------------------------------------------------------

说明.txt


数据库产品版本: Sql Server 2014


关于数据库的说明:

登录时应选择SQL Server身份验证模式。
用户名:sa
密码:空

Sql服务器身份验证模式应设置为:混合验证模式。
 需使用SQL Server身份验证模式,不能使用Windows身份验证模式。


对于考试所要求内容完成情况的说明:

1.命名规范和适当注释:
(1)工程名、包名、类名均按照Java编程规范命名。
(2)关键位置标有注释,如单击事件如何响应、何种方法导出数据、如何保存文件、按何种条件查询等。


2.页面设计:
(1)两个界面包括一个欢迎界面,一个操作界面。
(2)欢迎界面有欢迎消息与进入按钮。
(3)操作界面包括三个按钮(查询、保存、上传),一个输入框,一个表格显示框,若干文本框。


3.优化处理:
(1)运用了面向对象的方法,封装了若干个类如MyTableModel,MyFile,MyWindow,MyClientSocket,MyServerSocket等方法,详见工程文件。
(2)及时使用.close()方法关闭对象,释放了资源。
(3)运用了更多API中的接口、方法以完成功能设计。
(4)若server端成功打开,则会显示一条提示框“端口已打开”。
(5)将main方法单独迁移到MainTest类中测试。


4.图形界面的异常处理提示等友好交互:
(1)在进行查询前不可以点击保存到本地和上传服务器按钮。
(2)保存或上传失败会有提示,查询无结果会有提示,查询条件输入错误会有提示,不按顺序操作会有提示。


5.功能实现情况:
(1)查询按钮的单击事件使结果显示在JTable表格框中,支持模糊查询。
(2)实现了两个存储按钮的功能。保存是不覆盖的,且每次追加有标识。


*对功能的另外说明:
因JFileChooser未能正式实现,所以保存在服务器的文件统一命名为chaxunser.txt。
没有按照较繁琐的两次连接保存的方法存储为两个文件chaxunnoser.txt和chaxunnameser.txt。
但保存在本地的文件实现分为两个文件chaxunno.txt和chaxunname.txt。


以上是ReadMe说明。

--------------------------------------------------------分--割--线--------------------------------------------------------

具体GUI界面就不贴了,大体如此。

本来是想使用JFileChooser保存文件,由于只听了lecture,experiment上没有练习JFileChooser也就未使用。

考试难度不大,但是三个小时,时间紧张,还好是基本完成了。

自评:第一题完成度100%。第二题完成度85%。平时实验按时完成,质量无法自评。平时/考试三七开,希望最后能上90分。

------------------------------------------

临近数据结构考试,对一些二叉线索化、balance tree、多重邻接、十字链表等等算法还一知半解。

最近有点嗜睡,典型的考试月疲懒症。

以上是关于Java Client/Server 上传文件到服务器与保存文件到本地的主要内容,如果未能解决你的问题,请参考以下文章

文件上传漏洞

Java 网络编程

Java---网络编程

java命令行参数说明学习

vsftpd服务

云备份项目