java基础知识--IO篇

来源:互联网 发布:网络电视直播在线看 编辑:程序博客网 时间:2024/05/22 02:10

一、文件下载

  项目文件存入ambry文件服务器,并返回可访问url,利用url下载该文件。

public void downloadByURL(@Param("download")String download,@Param("description")String description,                              HttpServletRequest request, HttpServletResponse response){//这里description为文件名,用以下载的时候显示。        if(!description.endsWith(".zip")){            description = description+".zip";        }//对response头进行设置        response.reset();        response.setContentType("application/octet-stream");        response.setCharacterEncoding("UTF-8");        //设置文件下载是以附件的形式下载        response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", description));        try {            //根据文件url链接,获取文件字节数组            byte[] buffer = HTTPDownload.downLoadFromUrl(download);            //从response头获取输出流,并向里面写            OutputStream out = response.getOutputStream();            //向流里面写,此时浏览器便能监听到            out.write(buffer);            out.close();        } catch (IOException e) {            e.printStackTrace();        }    }
import java.net.HttpURLConnection;import java.net.URL;public static byte[]  downLoadFromUrl(String urlStr) throws IOException {        URL url = new URL(urlStr);        HttpURLConnection conn = (HttpURLConnection)url.openConnection();        //设置超时间为5秒        conn.setConnectTimeout(5*1000);        //得到文件的输入流        InputStream inputStream = conn.getInputStream();        //将输入流转为字节数组        byte[] buffer = readInputStream(inputStream);        return buffer;    }    /**     * 从输入流中获取字节数组     * @param inputStream     * @return     * @throws IOException     */    public static  byte[] readInputStream(InputStream inputStream) throws IOException {        byte[] buffer = new byte[4096];        int len = 0;        //造个输出流,用来输出字节数组        ByteArrayOutputStream bos = new ByteArrayOutputStream();        while((len = inputStream.read(buffer)) != -1) {            bos.write(buffer, 0, len);        }        bos.close();        inputStream.close();        return bos.toByteArray();    }

Content-disposition中Attachment和inline的区别

java web中下载文件时,我们一般设置 Content-Disposition 告诉浏览器下载文件的名称,是否在浏览器中内嵌显示.

  • Content-disposition: inline; filename=foobar.pdf
  • 表示浏览器内嵌显示一个文件
  • Content-disposition: attachment; filename=foobar.pdf
  • 表示会下载文件,如火狐浏览器中

这里写图片描述

但是我们使用的chrome,通常设置了默认下载地址,所以不会提示。如果没有设置,则会提示选择下载路径。

看如下代码 spring mvc中:

@ResponseBody    @RequestMapping(value = "/download",produces="application/octet-stream")    public byte[] downloadFile(HttpServletRequest request, HttpServletResponse response,String contentType2)            throws IOException {        byte[]bytes=FileUtils.getBytes4File("D:\\Temp\\cc.jpg");        response.addHeader("Content-Disposition", "inline;filename=\"a.jpg\"");        return bytes;    }

如上代码中是内嵌显示图片呢?还是会弹框下载呢?

答案是:弹框下载

为什么呢?设置为inline应该是内嵌显示啊!

因为response content type设置成了”application/octet-stream”

注意:我们说是内嵌显示还是下载,那 一定是针对可内嵌显示的类型 ,例如”image/jpeg”,”image/png”等.

看下面的例子:设置response content type为” image/jpeg “

@ResponseBody    @RequestMapping(value = "/download",produces="image/jpeg")    public byte[] downloadFile(HttpServletRequest request, HttpServletResponse response,String contentType2,String downloadType)            throws IOException {        byte[]bytes=FileUtils.getBytes4File("D:\\Temp\\cc.jpg");        response.addHeader("Content-Disposition", downloadType+";filename=\"a.jpg\"");        return bytes;    }

对于Content-type对照表可参照http://tool.oschina.net/commons

在浏览器中访问:http://localhost:8080/download?downloadType=inline 时就内嵌显示:
当在浏览器中访问:http://localhost:8080/download?downloadType=attachment 时就弹框下载.


二、文件上传

放一段hash大神的ambry文件上传。

public class HTTPUpload {    private static final Logger log = LoggerFactory.getLogger(HTTPUpload.class);    private final String ambryUrl;    private final String tmpFilePath;    public HTTPUpload(final String ambryUrl) {        this.ambryUrl = ambryUrl;//笔记一,笔记二1        this.tmpFilePath = StrUtils.makeString(HTTPUpload.class.getResource("").getFile().toString(), "tmp");        File file1 = new File(tmpFilePath);        //文件不存在则创建        if(!file1.exists()){            file1.mkdirs();            //设置文件权限            file1.setExecutable(true,false);            file1.setReadable(true,false);            file1.setWritable(true,false);        }        Scheduler scheduler = new Scheduler();        scheduler.schedule("50 13 * * *", new DeleteTask(tmpFilePath));    }    public String uploadFile(MultipartFile file1, long size, String ServiceId, String owner, String fileFormat,                             String description) {        HttpURLConnection connection = null;        OutputStream os = null;        DataInputStream is = null;        InputStream inputStream = null;        String message = "empty";        int count = 0;        while (count <= 3) {            try {                //笔记二2                File file = new File(StrUtils.makeString(tmpFilePath, "/", file1.getOriginalFilename()));                //笔记二3                file1.transferTo(file);                //笔记三                if (!fileFormat.equals("image")) {                    inputStream = new StreamGenerator(file, tmpFilePath).getInputStream();                } else {                    inputStream = new FileInputStream(file);                }                //笔记四                int length = inputStream.available();                //笔记五                connection = (HttpURLConnection) new URL(ambryUrl).openConnection();                connection.setRequestMethod("POST");                connection.setRequestProperty("Content-Type", "application/octet-stream");                //设置是否从httpUrlConnection读入,默认情况下是true;                connection.setDoOutput(true);                //设置是否向httpUrlConnection输出,默认为false                connection.setDoInput(true);                connection.setRequestProperty("x-ambry-blob-size", length + "");                connection.addRequestProperty("x-ambry-service-id", ServiceId);                connection.addRequestProperty("x-ambry-owner-id", owner);                connection.addRequestProperty("x-ambry-content-type", fileFormat);                connection.addRequestProperty("x-ambry-um-description", description);                connection.connect();                //笔记六                os = new BufferedOutputStream(connection.getOutputStream());                byte[] buffer = new byte[4096];                int bytes_read;                //只要可以读取到数据,就输出写到buffer中                while ((bytes_read = inputStream.read(buffer)) != -1) {                    os.write(buffer, 0, bytes_read);                }                //数据读取完关闭inputStream                os.close();                inputStream.close();                //笔记七                String location = connection.getHeaderField("Location");                return StrUtils.makeString(ambryUrl, location);            } catch (Throwable e) {                //笔记八                count++;                try {                    TimeUnit.SECONDS.sleep(1L);                } catch (InterruptedException e1) {                }                log.warn("file-upload-failed:" + JSON.toJSONString(file1) + "|||" + "{ServiceId:" + ServiceId + ",owner:" + owner + ",fileFormat:" + fileFormat + ",description:" + description + "}");                log.warn(ExceptionUtils.getStackTrace(e));            } finally {                try {                    if (os != null) {                        os.close();                    }                } catch (IOException e) {                    log.warn(ExceptionUtils.getStackTrace(e));                }                try {                    if (is != null) {                        is.close();                    }                } catch (IOException e) {                    log.warn(ExceptionUtils.getStackTrace(e));                }                if (connection != null) {                    connection.disconnect();                }            }        }        return null;    }}
笔记一

Class.getResource()与Class.getResourceAsStream()方法,但很多人还是不太懂它的用法,因为很多人(比如不久前的我)都不知道应该传怎么样的参数给它,当然,有些人己经用得如火纯青,这些人是不需要照顾的,在此仅给不会或者还不是很熟的人解释一点点。

比如我们有以下目录

|–project

|--src    |--javaapplication        |--Test.java        |--file1.txt    |--file2.txt|--build     |--javaapplication        |--Test.class        |--file3.txt    |--file4.txt

在上面的目录中,有一个src目录,这是JAVA源文件的目录,有一个build目录,这是JAVA编译后文件(.class文件等)的存放目录

那么,我们在Test类中应该如何分别获得

file1.txt file2.txt file3.txt file4.txt这四个文件呢?

首先讲file3.txt与file4.txt

file3.txt:

方法一:File file3 = new File(Test.class.getResource(“file3.txt”).getFile());

方法二:File file3 = new File(Test.class.getResource(“/javaapplication/file3.txt”).getFile());

方法三:File file3 = new File(Test.class.getClassLoader().getResource(“javaapplication/file3.txt”).getFile());

file4.txt:

方法一:File file4 = new File(Test.class.getResource(“/file4.txt”).getFile());

方法二:File file4 = new File(Test.class.getClassLoader().getResource(“file4.txt”).getFile());

很好,我们可以有多种方法选择,但是file1与file2文件呢?如何获得?

答案是,你只能写上它们的绝对路径,不能像file3与file4一样用class.getResource()这种方法获得,它们的获取方法如下

假如整个project目录放在c:/下,那么file1与file2的获取方法分别为

file1.txt

方法一:File file1 = new File(“c:/project/src/javaapplication/file1.txt”);

方法二:。。。没有

file2.txt

方法一:File file2 = new File(“c:/project/src/file2.txt”);

方法二:。。。也没有

总结一下,就是你想获得文件,你得从最终生成的.class文件为着手点,不要以.java文件的路径为出发点,因为真正使用的就是.class,不会拿个.java文件就使用,因为java是编译型语言嘛

笔记二

在初始化HTTPUpload对象的时候,会在该类目录下创建个临时目录,D:/projectSource/*/target/classes/com/*/ambry/tmp,见笔记二1。
在使用上传方法时,在前面的目录下根据文件名new一个File,但file对象内容为空,见笔记二2。
将传过来的文件写入file对象中,见笔记二3。

笔记三

如果文件不是image类型,则将文件压缩为zip之后得到输入流。如果是图片,则直接得到图片文件的输入流。
调用如下方法,返回zip文件的输入流

import java.util.zip.ZipEntry;import java.util.zip.ZipOutputStream;public class StreamGenerator {    private static File file;    private static String tempFilePath;    public StreamGenerator(File file,String tempFilePath){        this.file = file;        this.tempFilePath = tempFilePath;    }    /**     * 压缩传入的文件,返回流     * @return inputstream     */    public static InputStream getInputStream() {        String zipName =  IDGenerator.getID(Constants.PUBLIC_COMPONENT_SYSTEM);        //判断是否有文件夹,如果没有就创建        File tempF = new File(tempFilePath);        if(!tempF.exists()){            tempF.mkdirs();        }        /**         * 压缩并在指定目录生成临时zip文件         */        byte[] buffer = new byte[4096];        ZipOutputStream out = null;        try {            //在临时目录下根据前面生成的zip包名,new一个fileoutput(zipoutput)流            out = new ZipOutputStream(new FileOutputStream(tempFilePath + zipName + ".zip"));            FileInputStream fileInput = new FileInputStream(file);            //向流中加入zip实体(此时为空,名为文件名)            out.putNextEntry(new ZipEntry(file.getName()));            int temp = 0;            //读取文件并打包            while ((temp = fileInput.read(buffer)) > 0) {                out.write(buffer, 0, temp);            }            out.closeEntry();            fileInput.close();            out.close();        } catch(Exception ex){            ex.printStackTrace();        }        /**         * 把压缩包读取为输出流         */         //得到这个有内容的zip对象        File filezip = new File(tempFilePath + zipName + ".zip");        ByteArrayOutputStream byteOut = null;        try {            byteOut = new ByteArrayOutputStream();            FileInputStream FileIn = new FileInputStream(filezip);            BufferedInputStream bufferInput = new BufferedInputStream(FileIn);            int k = bufferInput.read();            while (k != -1) {                byteOut.write(k);                k = bufferInput.read();            }            bufferInput.close();            FileIn.close();        } catch(Exception ex) {            ex.printStackTrace();        }        /**         * 输出流转为uploadFile方法的输入流         */        ByteArrayInputStream inStream = new ByteArrayInputStream(byteOut.toByteArray());        return inStream;    }}

此处为他人所写。根据输入流得到zip的输出流,得到字节数组,然后再回到输入流,感觉多此一举,也许可能存在流转换的问题,以后有时间去验证。

笔记四

获得文件的可用大小,此处为ambry用,如果传错会报错。

笔记五

向ambry发送http请求(post)

笔记六

connection.getOutputStream()通过http连接,获取输出流。并包装成输出字节流,将zip或图片获取的输入流,写入此输出流。

笔记七

location头里面的东西,就是文件存储后的唯一标识。

笔记八

三次尝试机制,每次失败延迟1毫秒:TimeUnit.SECONDS.sleep(1L)。

原创粉丝点击