下载文件
下面的代码展现了如何从页面上下载服务器上的文件。服务器上文件以windows系统上的HOSTS文件举例。
主要思路是利用FileInputStream获得服务器上文件的句柄,定义一个缓冲区字节数组,每次读一个数组长度的字节到输出设备,直到读完。
@RequestMapping(value = "/downloadExistFile.do")
public void downloadExistFile(HttpServletRequest request, HttpServletResponse response) {
FileInputStream fileInputStream = null;
ServletOutputStream servletOutputStream = null;
String filePath = "C:\\Windows\\System32\\drivers\\etc\\HOSTS";
String fileName = "HOSTS";
try {
response.setContentType("application/x-msdownload;");
response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("GBK"), "GBK"));
// 将本地文件装载到内存
fileInputStream = new FileInputStream(filePath);
// 实例化输出流
servletOutputStream = response.getOutputStream();
byte[] buff = new byte[2048];
int bytesRead;
// 每次尝试读取buff.length长字节,直到读完、bytesRead为-1
while ((bytesRead = fileInputStream.read(buff, 0, buff.length)) != -1) {
// 每次写bytesRead长字节
servletOutputStream.write(buff, 0, bytesRead);
}
// 刷新缓冲区
servletOutputStream.flush();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
if (servletOutputStream != null) {
try {
servletOutputStream.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
}
}
文件解密
如果文件下载前需要进行解密,那么就利用ByteArrayOutputStream做缓冲,把文件字节流先写入到byteArrayOutputStream对象里。读完后利用toByteArray方法将读完的字节转换为字节数组,并对字节数据进行加密,最后再写入到输出设备里。代码变化如下:
@RequestMapping(value = "/fileDecryptDo.do")
public void fileDecryptDo(HttpServletRequest request, HttpServletResponse response) {
// 可以捕获内存缓冲区的数据,转换成字节数组。
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
InputStream inputStream = null;
OutputStream outputStream = null;
String filePath = "C:\\Windows\\System32\\drivers\\etc\\HOSTS";
String fileName = "HOSTS";
try {
response.setContentType("application/x-msdownload;");
response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("GBK"), "GBK"));
// 这里假定待解密文件一般是字节流形式,这里通过FileInputStream将本地文件装载到内存
inputStream = new FileInputStream(filePath);
// 实例化输出流
outputStream = response.getOutputStream();
byte[] buf = new byte[4096 * 2];
int bytesRead;
// 每次尝试读取buff.length长字节,直到读完、bytesRead为-1
while ((bytesRead = inputStream.read(buf)) != -1) {
byteArrayOutputStream.write(buf, 0, bytesRead);
}
// 刷新缓冲区
byteArrayOutputStream.flush();
// 对读取的字节做解密,并写到设备
outputStream.write(decrypt(byteArrayOutputStream.toByteArray()));
// 刷新缓冲区
outputStream.flush();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
} finally {
if (byteArrayOutputStream != null) {
try {
byteArrayOutputStream.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
}
}
public byte[] decrypt(byte[] value) {
// 解密实现略去
return value;
}
文件加密
文件加密的场景稍有不同,通常待加密文件都是字符明文文件,这里就需要通过转换流InputStreamReader将字符流转换为字节流。而Reader所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求,因此通常用BufferedReader包装一下。
再用StringBuilder接收BufferedReader.readLine()方法读取到字符串,并对字符串进行加密,最后写到输出设备中。
public void fileEncryptDo(HttpServletRequest request, HttpServletResponse response) {
BufferedReader bufferedReader = null;
OutputStream outputStream = null;
String filePath = "C:\\Windows\\System32\\drivers\\etc\\HOSTS";
String fileName = "HOSTS";
try {
response.setContentType("application/x-msdownload;");
response.setHeader("Content-disposition", "attachment; filename=" + new String(fileName.getBytes("GBK"), "GBK"));
// 这里假定待解密是字符文件形式,这里通过转换流InputStreamReader将本地文件装载到内存、并用 BufferedReader包装。
// InputStreamReader将字节流转换为字符流,是字节流通向字符流的桥梁。
bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "GBK"));
// 实例化输出流
outputStream = response.getOutputStream();
String lineTxt;
StringBuilder content = new StringBuilder();
// 每次尝试读取一行字符,直到读完、lineTxt为null
while ((lineTxt = bufferedReader.readLine()) != null) {
content.append(lineTxt);
}
// 对读取的字符做加密,并写到设备
outputStream.write(encrypt(content.toString().getBytes("GBK")));
// 刷新缓冲区
outputStream.flush();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
Help.log_error(getClass(), "IOException occured...", e);
}
}
}
}
public byte[] encrypt(byte[] value) {
// 加密实现略去
return value;
}