今天小编给大家分享一下Java怎么从本地文件复制到网络文件上传的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
文件复制
文件复制: 将一个本地文件从一个目录,复制到另一个目录。(通过本地文件系统)
主要代码
package dragon; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * 本地文件复制: * 将文件从一个地方复制到另一个地方。 * * @author Alfred * */ public class FileCopy { public FileCopy() {} public void fileCopy(String target, String output) throws IOException { File targetFile = new File(target); File outputPath = new File(output); this.init(targetFile, outputPath); /**注意这里使用了 try with resource 语句,所以不需要显示的关闭流了。 * 而且,再关闭流操作中,会自动调用 flush 方法,如果不放心, * 可以在每个write 方法后面,强制刷新一下。 * */ try ( BufferedInputStream bis = new BufferedInputStream(new FileInputStream(targetFile)); //创建输出文件 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(outputPath, "copy"+targetFile.getName())))){ int hasRead = 0; byte[] b = new byte[1024]; while ((hasRead = bis.read(b)) != -1) { bos.write(b, 0, hasRead); } } System.out.println("文件复制成功"); } //数据校验及初始化工作 private void init(File targetFile, File outputPath) throws FileNotFoundException { if (!targetFile.exists()) { throw new FileNotFoundException("目标文件不存在:"+targetFile.getAbsolutePath()); } else { if (!targetFile.isFile()) { throw new FileNotFoundException("目标文件是一个目录:"+targetFile.getAbsolutePath()); } } if (!outputPath.exists()) { if (!outputPath.mkdirs()) { throw new FileNotFoundException("无法创建输出路径:"+outputPath.getAbsolutePath()); } } else { if (!outputPath.isDirectory()) { throw new FileNotFoundException("输出路径不是一个目录:"+outputPath.getAbsolutePath()); } } } }
测试类
package dragon; import java.io.IOException; public class FileCopyTest { public static void main(String[] args) throws IOException { String target = "D:/DB/BuilderPattern.png"; String output = "D:/DBC/dragon/"; FileCopy copy = new FileCopy(); copy.fileCopy(target, output); } }
执行结果
注意:右边文件是复制的结果,左边的不是。(下面会提到!)
说明
上面的代码只是将一个本地文件从一个目录,复制到另一个目录,还是比较简单的,这只是一个原理性的代码,来说明输入输出流的应用。将文件从一个地方复制到另一个地方。
网络文件传输(TCP)
**网络文件传输(TCP):**使用套接字(TCP)进行演示,文件从一个地方复制到另一个地方。(通过网络的方式。)
主要代码
Server
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; public class Server { public static void main(String[] args) throws IOException { try ( ServerSocket server = new ServerSocket(8080)){ Socket client = server.accept(); //开始读取文件 try ( BufferedInputStream bis = new BufferedInputStream(client.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:/DBC/dragon", System.currentTimeMillis()+".jpg")))){ int hasRead = 0; byte[] b = new byte[1024]; while ((hasRead = bis.read(b)) != -1) { bos.write(b, 0, hasRead); } } System.out.println("文件上传成功。"); } } }
Client
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.Socket; import java.net.UnknownHostException; public class Client { public static void main(String[] args) throws UnknownHostException, IOException { try (Socket client = new Socket("127.0.0.1", 8080)){ File file = new File("D:/DB/netFile/001.jpg"); //开始写入文件 try ( BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream())){ int hasRead = 0; byte[] b = new byte[1024]; while ((hasRead = bis.read(b)) != -1) { bos.write(b, 0, hasRead); } } } } }
执行效果
执行程序
注意:这个上传文件的目录和本地文件复制是在同一个目录,但是使用的方式不一样,文件的命名方式不一样,使用的是当前的毫秒数。 复制前文件
复制后文件
说明
通过网络的方式使用流,使用传输层的TCP协议,绑定了 8080 端口,这里需要一些网络的知识,不过都是最基本的知识。可以看出来,上面这个 Server端和 Client端的代码很简单,甚至都没有实现传输文件的后缀名!(哈哈,其实是我对套接字编程不太熟悉,传输文件名的话,我一开始尝试,但是没有成功。不过这个不影响这个例子,套接字我会抽时间来看的。哈!) 注意这里我要表达的意思通过网络将文件从一个地方复制到另一个地方。(使用较为的是传输层的协议)
网络文件传输(HTTP)
HTTP 是建立在 TCP/IP 协议之上的应用层协议,传输层协议使用起来感觉还是比较麻烦的,不如应用层协议用起来方便。
网络文件传输(HTTP): 这里使用 Servlet(3.0以上)(JSP)技术来举例,就以我们最常使用的文件上传为例。
使用 HTTP 协议将文件从一个地方复制到另一个地方。
使用 apache 组件实现文件上传
注意:因为原始的通过 Servlet 上传文件较为麻烦,现在都是使用一些组件来达成这个文件上传的功能的。(我没有找到文件上传最原始的写法,想必应该是很繁琐的吧!) 这里使用两个jar包:
commons-fileupload-1.4.jar
commons-io-2.6.jar
注意:在 apache 网站可以下载到。
上传文件的 Servlet
package com.study; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * Servlet implementation class UploadServlet */ @WebServlet("/UploadServlet") public class UploadServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //如果不是文件上传的话,直接不处理,这样比较省事 if (ServletFileUpload.isMultipartContent(request)) { //获取(或者创建)上传文件的路径 String path = request.getServletContext().getRealPath("/image"); File uploadPath = new File(path); if (!uploadPath.exists()) { uploadPath.mkdir(); } FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> items; try { items = upload.parseRequest(request); Iterator<FileItem> it = items.iterator(); while (it.hasNext()) { FileItem item = it.next(); //处理上传文件 if (!item.isFormField()) { String filename = new File(item.getName()).getName(); System.out.println(filename); File file = new File(uploadPath, filename); item.write(file); response.sendRedirect("success.jsp"); } } } catch (Exception e) { e.printStackTrace(); } } } }
上传文件的jsp中,只需要一个form表单即可。
<h2>文件上传</h2> <form action="NewUpload" method="post" enctype="multipart/form-data"> <input type="file" name="image"> <input type="submit" value="上传"> </form>
运行效果
说明
虽然这样处理对于上传文件很好,但是因为使用的都是较为成熟的技术,对于想了解输入输出流的我们来说,就不是那么好了。从这个例子中,基本上看不到输入输出流的用法了,都被封装起来了。
使用 Servlet 3.0 以后的新技术实现文件上传
package com.study; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * Servlet implementation class FileUpload */ @MultipartConfig @WebServlet("/FileUpload") public class FileUpload extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part part = request.getPart("image"); String header = part.getHeader("Content-Disposition"); System.out.println(header); String filename = header.substring(header.lastIndexOf("filename="")+10, header.lastIndexOf(""")); String fileSuffix = filename.lastIndexOf(".") != -1 ? filename.substring(filename.lastIndexOf(".")) : ""; String uploadPath = request.getServletContext().getRealPath("/image"); File path = new File(uploadPath); if (!path.exists()) { path.mkdir(); } filename = UUID.randomUUID()+fileSuffix; try ( BufferedInputStream bis = new BufferedInputStream(part.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(path, filename)))){ int hasRead = 0; byte[] b = new byte[1024]; while ((hasRead = bis.read(b)) != -1) { bos.write(b, 0, hasRead); } } response.sendRedirect("success.jsp"); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
使用 Servlet 3.0 的新特性实现,这里使用了
@MultipartConfig注解。(如果不使用这个注解,会无法正常工作!感兴趣的,可以多去了解一下。)
注意:下面这段代码,这里我舍近求远了,但是这正是我想要看到的。同样是输入输出流,注意这个和上面的几个例子进行对比。
try ( BufferedInputStream bis = new BufferedInputStream(part.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(path, filename)))){ int hasRead = 0; byte[] b = new byte[1024]; while ((hasRead = bis.read(b)) != -1) { bos.write(b, 0, hasRead); } }
不使用 apache 组件的更为简单的方式是下面这种:
package com.study; import java.io.File; import java.io.IOException; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.annotation.MultipartConfig; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.Part; /** * Servlet implementation class NewUpload */ @MultipartConfig @WebServlet("/NewUpload") public class NewUpload extends HttpServlet { private static final long serialVersionUID = 1L; protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Part part = request.getPart("image"); String header = part.getHeader("Content-Disposition"); System.out.println(header); String filename = header.substring(header.lastIndexOf("filename="")+10, header.lastIndexOf(""")); String fileSuffix = filename.lastIndexOf(".") != -1 ? filename.substring(filename.lastIndexOf(".")) : ""; String uploadPath = request.getServletContext().getRealPath("/image"); File path = new File(uploadPath); if (!path.exists()) { path.mkdir(); } filename = uploadPath+File.separator+System.currentTimeMillis()+UUID.randomUUID().toString()+fileSuffix; part.write(filename); response.sendRedirect("success.jsp"); } }
真正写入文件的只有这一步了,前面全是处理文件名和上传文件路径相关的代码。使用 HTTP 的这三种方式都有处理文件名和上传文件路径这段代码。
如果通过这段代码,那就更看不出什么东西来了,只知道这样做,一个文件就会被写入相应的路径。
part.write(filename);