Почему мое изображение выходит искаженным?

У меня есть код 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();
  }

Может ли кто-нибудь заметить, что я делаю не так?

Ваше здоровье, Ли

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
0
657
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

Не знаю, какая разница, но похоже, что сигнатуры методов не совпадают. Метод 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);

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

Другие вопросы по теме