У меня есть код Java, использующий сервлет и Apache Commons FileUpload для загрузки файла в заданный каталог. Он отлично работает для символьных данных (например, текстовых файлов), но файлы изображений выходят с искажениями. Я могу их открыть, но изображение выглядит не так, как должно. Вот мой код:
Сервлет
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String customerPath = "\leetest\";
// Check that we have a file upload request
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload();
// Parse the request
FileItemIterator iter = upload.getItemIterator(request);
while (iter.hasNext()) {
FileItemStream item = iter.next();
String name = item.getFieldName();
if (item.isFormField()) {
// Form field. Ignore for now
} else {
BufferedInputStream stream = new BufferedInputStream(item
.openStream());
if (stream == null) {
LOGGER
.error("Something went wrong with fetching the stream for field "
+ name);
}
byte[] bytes = StreamUtils.getBytes(stream);
FileManager.createFile(customerPath, item.getName(), bytes);
stream.close();
}
}
}
} catch (Exception e) {
throw new UploadException("An error occured during upload: "
+ e.getMessage());
}
}
StreamUtils.getBytes (поток) выглядит так:
public static byte[] getBytes(InputStream src, int buffsize)
throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buff = new byte[buffsize];
while (true) {
int nBytesRead = src.read(buff);
if (nBytesRead < 0) {
break;
}
byteStream.write(buff);
}
byte[] result = byteStream.toByteArray();
byteStream.close();
return result;
}
И, наконец, FileManager.createFile выглядит так:
public static void createFile(String customerPath, String filename,
byte[] fileData) throws IOException {
customerPath = getFullPath(customerPath + filename);
File newFile = new File(customerPath);
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
FileOutputStream outputStream = new FileOutputStream(newFile);
outputStream.write(fileData);
outputStream.close();
}
Может ли кто-нибудь заметить, что я делаю не так?
Ваше здоровье, Ли




Вы уверены, что изображение не искажается или что вы не теряете несколько пакетов по пути?
Не знаю, какая разница, но похоже, что сигнатуры методов не совпадают. Метод getBytes(), вызываемый в вашем методе doPost(), имеет только один аргумент:
byte[] bytes = StreamUtils.getBytes(stream);
в то время как источник метода, который вы включили, имеет два аргумента:
public static byte[] getBytes(InputStream src, int buffsize)
Надеюсь, это поможет.
Можете ли вы выполнить контрольную сумму исходного файла и загруженного файла и посмотреть, есть ли какие-либо немедленные различия?
Если есть, то вы можете посмотреть на выполнение сравнения, чтобы определить точные части файла, которые отсутствуют, и изменены.
На ум приходят начало или конец потока или порядок следования байтов.
Одна вещь, которая мне не нравится, находится в этом блоке StreamUtils.getBytes ():
1 while (true) {
2 int nBytesRead = src.read(buff);
3 if (nBytesRead < 0) {
4 break;
5 }
6 byteStream.write(buff);
7 }
В строке 6 он записывает весь буфер, независимо от того, сколько байтов было прочитано. Я не уверен, что так будет всегда. Правильнее было бы так:
1 while (true) {
2 int nBytesRead = src.read(buff);
3 if (nBytesRead < 0) {
4 break;
5 } else {
6 byteStream.write(buff, 0, nBytesRead);
7 }
8 }
Обратите внимание на «else» в строке 5, а также на два дополнительных параметра (начальная позиция индекса массива и длина для копирования) в строке 6.
Я мог представить, что для больших файлов, таких как изображения, буфер возвращается до того, как он будет заполнен (возможно, он ждет большего). Это означает, что вы непреднамеренно записываете старые данные, которые оставались в хвостовой части буфера. Это почти наверняка происходит большую часть времени в EoF, предполагая, что буфер> 1 байт, но дополнительные данные в EoF, вероятно, не являются причиной вашего повреждения ... это просто нежелательно.
Я бы просто использовал Commons io. Тогда вы могли бы просто сделать IOUtils.copy (InputStream, OutputStream);
У него есть много других полезных служебных методов.