Загрузка огромного файла с помощью веб-приложения

Среда для данной цели в настоящее время недоступна, поэтому я не могу попробовать что-то и должен полагаться только на анализ!

Моя цель может быть разбита на следующие отдельные шаги:

  1. Загрузка огромных файлов (до 100 ГБ) с использованием глупой страницы «Загрузить файл» — от этого никуда не деться, поскольку пользователи хотят (тупой) внешний интерфейс и не хотят передавать файл по ftp и т. д.
  2. Веб-приложение, которое обеспечивает вышеуказанный внешний интерфейс, будет размещено на низкоуровневой машине - 2 ГБ ОЗУ и 40 ГБ на жестком диске, и это веб-приложение НЕ БУДЕТ СОХРАНЯТЬ какую-либо часть огромного файла на локальном компьютере, но должно "быстро" записать его на высокопроизводительная удаленная машина Linux

Для каждого шага я выделяю свой подход, опасения и вопросы:

  • Я сослался на эту тему, которая меня смутила, поскольку я планировал создать тупое веб-приложение, используя Spring MVC с загрузить страницу - нужно ли мне заходить в HTML5 и т. д. или будет достаточно простого веб-приложения?

  • Учитывая 2 ГБ ОЗУ, веб-приложение получит менее 1 ГБ. Я боюсь, что 'OutOfMemoryError' возможен, если код не написан строго - я должен убедиться, что из потока небольшой кусок, скажем, 10 МБ, должен быть прочитан за раз и записан в файл удаленной машины Linux. Предполагая, что я нахожусь в doPost(...) сервлета контроллера, я немного прочитал о том, как действовать, и запутался:

          /**
             * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
             *      response)
             */
            protected void doPost(HttpServletRequest request,
                    HttpServletResponse response) throws ServletException, IOException {
                // TODO Auto-generated method stub
    
                InputStream fis = request.getInputStream();
                int i = 0;
    
                /* Approach - 1 : Plain old byte-by-byte method */
                Socket socket = new Socket("192.168.90.20", 22);
                OutputStream remoteOpStream = socket.getOutputStream();
    
                while ((i = fis.read()) != -1) {
                    remoteOpStream.write(i);
                }
    
                /* clean-up */
    
                /* Approach - 2 : NIO */
                ByteBuffer byteBuff = ByteBuffer.allocate(10000);/* read 10MB of data */
    
                ReadableByteChannel rdbyc = Channels.newChannel(request
                        .getInputStream());
    
                File remoteFile = new File("192.168.90.20/Remote_Linux_Folder");/*
                                                                                 * Dunno
                                                                                 * how
                                                                                 * to
                                                                                 * create
                                                                                 * a
                                                                                 * File
                                                                                 * on a
                                                                                 * remote
                                                                                 * Linux
                                                                                 * machine
                                                                                 */
                FileOutputStream remoteFos = new FileOutputStream(remoteFile);
                FileChannel writableChannel = remoteFos.getChannel();
    
                while (true/* dunno how to loop till all the data is read! */) {
                    rdbyc.read(byteBuff);
                    writableChannel.write(byteBuff);
                }
    
                /* clean-up */
    
            }
    

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

Я считаю, что NIO — это правильный путь, но я не могу определить, как я должен действовать — пожалуйста, укажите то же самое.


person Kaliyug Antagonist    schedule 19.09.2012    source источник
comment
Ни Sevlet API, ни стандартный java.io.File IO не предоставляют неблокирующих API. На большинстве операционных систем файловый ввод-вывод блокируется, но может использоваться с неблокирующими каналами, но фактический ввод-вывод при его выполнении блокируется (обычно это слишком быстро, чтобы заметить разницу из-за буферного кеша операционной системы и т. д. ...). Если вам действительно нужен неблокирующий дизайн файлового ввода-вывода, посмотрите на AIO (модель асинхронного ввода-вывода), а не на NIO. Но если ваш пункт назначения для данных находится в сети с использованием сокета, тогда NIO правильный.   -  person Darryl Miles    schedule 20.09.2012


Ответы (1)


Я бы реализовал FixedSizeQueue и popAll() данные из QueueStream на другой компьютер. Вероятно, он имеет двойную буферизацию, просто чтобы обеспечить смягчение проблем с сетью / пропускной способностью.

person Aniket Inge    schedule 19.09.2012
comment
Привет, прототип Старк. Извините, но я не понял, на что вы намекаете - пожалуйста, уточните! - person Kaliyug Antagonist; 20.09.2012