Почему мой образ искажается? - PullRequest
4 голосов
/ 03 сентября 2008

У меня есть некоторый Java-код, использующий сервлет и Apache Commons FileUpload для загрузки файла в заданный каталог. Он хорошо работает с символьными данными (например, текстовыми файлами), но файлы изображений выходят искаженными. Я могу открыть их, но изображение не выглядит так, как должно. Вот мой код:

Servlet

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 (stream) выглядит так:

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();
  }

Кто-нибудь может заметить, что я делаю неправильно?

Cheers, Lee

Ответы [ 5 ]

4 голосов
/ 03 сентября 2008

Одна вещь, которая мне не нравится, здесь в этом блоке от 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, вероятно, не являются причиной вашего повреждения ... это просто нежелательно.

1 голос
/ 04 сентября 2008

Я бы просто использовал commons io Тогда вы могли бы просто сделать IOUtils.copy (InputStream, OutputStream);

У него много других полезных служебных методов.

0 голосов
/ 03 сентября 2008

Я не знаю, какое это имеет значение, но, похоже, существует несоответствие сигнатур методов. Метод getBytes(), вызываемый в вашем методе doPost(), имеет только один аргумент:

byte[] bytes = StreamUtils.getBytes(stream);

в то время как источник метода, который вы включили, имеет два аргумента:

public static byte[] getBytes(InputStream src, int buffsize)

Надеюсь, это поможет.

0 голосов
/ 03 сентября 2008

Можете ли вы выполнить контрольную сумму для вашего исходного файла и загруженного файла и посмотреть, есть ли какие-либо непосредственные различия?

Если есть, то вы можете посмотреть на выполнение сравнения, чтобы определить точные части файла, которые отсутствуют, изменены.

Вещи, которые приходят на ум, это начало или конец потока, или endianness.

0 голосов
/ 03 сентября 2008

Вы уверены, что изображение не искажено или вы не пропускаете какие-то пакеты при входе?

...