Загрузка файла в основное место и одновременное чтение и запись одного и того же файла в несколько дополнительных мест

мне нужно выполнить задачу, как показано ниже: -

1). Загрузка файла в основное место: -

Я хочу читать из файла и записывать его в основное место (удаленный файловый сервер).

2). Загрузка файла в несколько дополнительных мест: -

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

Я пробовал приведенную ниже программу для вышеуказанного подхода: -

BufferedInputStream bin = null;
        ReadableByteChannel channel = null;
        int bufferSize = 1048576;
        int readBufferSize = 1024*4;
        java.nio.ByteBuffer byteBuffer = java.nio.ByteBuffer.allocate(readBufferSize);
        InputStream is = new FileInputStream(new File("D:\\Harisingh\\300MB.txt"));

        bin = new BufferedInputStream(is,bufferSize);
        channel = Channels.newChannel(bin);
        int retryCnt = 0;
        ByteArrayOutputStream baOS = new ByteArrayOutputStream(bufferSize);
        int totalBytes=0;
        int itrCount=0;
        int maxIterateCnt = 1;
        int len;
        //primary location writing
        SmbFile smbFile = new SmbFile("smb://user:[email protected]/data/Harisingh/collab_4_1_4/primary.txt");
        BufferedOutputStream bFout = new BufferedOutputStream(new SmbFileOutputStream(smbFile));

        SmbFileInputStream fis = new SmbFileInputStream("smb://user:[email protected]/data/Harisingh/collab_4_1_4/primary.txt");
        BufferedInputStream binPrimary = new BufferedInputStream(fis);

        SmbFileOutputStream secLocation1= new SmbFileOutputStream(new SmbFile("smb://user:[email protected]/data/Harisingh/collab_4_1_4/Secondary1.txt"));
        SmbFileOutputStream secLocation2 = new SmbFileOutputStream(new SmbFile("smb://user:[email protected]/data/Harisingh/collab_4_1_4/Secondary2.txt"));
        SmbFileOutputStream secLocation3 = new SmbFileOutputStream(new SmbFile("smb://user:[email protected]/data/Harisingh/Secondary/Secondary3.txt"));
        try {
            if (bufferSize > readBufferSize){
                maxIterateCnt = bufferSize/readBufferSize;
            }
            while((len=channel.read(byteBuffer))>=0) 
            {
                itrCount++;
                totalBytes+=len;
                baOS.write(byteBuffer.array(),0,len);
                if (itrCount>=maxIterateCnt)
                {
                    //primary location writing
                    try{
                        bFout.write(baOS.toByteArray(),0,totalBytes);
                    }catch(Exception se)
                    {
                    }

                    // secondary location writing
                    new Thread(){
                           public void run(){
                              System.out.println("Thread Running");
                              try {
                                int count;
                                byte[] readByteArray = new byte[1024*4];
                                while ((count = binPrimary.read(readByteArray)) != -1)
                                    {
                                        secLocation1.write(readByteArray, 0, count);
                                        secLocation2.write(readByteArray, 0, count);
                                        secLocation3.write(readByteArray, 0, count);
                                        readByteArray = new byte[1024*4];
                                        count= 0;
                                    }
                            } catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                          }
                      }.start();
                    totalBytes=0;
                    baOS.reset();
                    itrCount=0;
                }
                byteBuffer.clear();
            }

            //primary location writing
            try{
                bFout.write(baOS.toByteArray(),0,totalBytes);
            }catch(Exception se)
            {
            }
            bFout.flush();
            bFout.close();
            int count;
            // secondary location writing
            new Thread(){
                public void run(){
                  System.out.println("Thread Running");
                  try {
                    int count;
                    byte[] readByteArray = new byte[1024*4];
                    while ((count = binPrimary.read(readByteArray)) != -1)
                    {
                            secLocation1.write(readByteArray, 0, count);
                            secLocation2.write(readByteArray, 0, count);
                            secLocation3.write(readByteArray, 0, count);
                            readByteArray = new byte[1024*4];
                            count= 0;
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                }
              }.start();

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

К вашему сведению

Этот вопрос относится только к потоку io. Это не относится к JCIFS, поэтому вы можете использовать ту же программу с простым потоком io, не требуя потока smb io. Не могли бы вы помочь мне разобраться в этом?

Вы пытались рассматривать свои второстепенные местоположения как основные? Я имею в виду обернуть SmbFileOutputStream в BufferedOutputStream для secLocation1, secLocation2 и secLocation3 и не забыть сбросить

VitalyZ 01.05.2018 16:12

@VitalyZ Спасибо за быстрый ответ. Теперь он отлично работает с переносом SmbFileOutputStream в BufferedOutputStream.

Harisingh Rajput 02.05.2018 08:47

@VitalyZ В соответствии с предыдущим комментарием, он работал нормально, заключая SmbFileOutputStream в BufferedOutputStream и промывая, но теперь стало известно, что размер файла кажется одинаковым для всех вторичных местоположений, но содержимое файла отличается и его не соответствует. Я сравнил MD5 вторичных файлов, но для всех он выглядит по-разному. Не могли бы вы помочь мне разобраться, почему размер файла такой же, но содержимое файла отличается. Кажется, что все еще что-то не так с записью файла.

Harisingh Rajput 02.05.2018 14:46

Каждый раз, когда вы пишете в первичный, вы создаете поток, который будет записывать все вторичные файлы заново с самого начала? Я думаю, вам следует отслеживать, сколько байтов было записано в первичный, сколько вы прочитали из первичного в вторичный и поиграться с чтением смещения. Также я не знаю, есть ли реальная выгода от вторичной записи в параллельных потоках, только сбивает с толку обработку. 1. Чтение файла, 2. WritePR, 3. Сброс, 4. ReadPR, 5. WriteSEC, 6. WriteSEC, 7. WriteSEC, 8. Очистка, 9. Повторить.

Jokkeri 03.05.2018 14:35

@Jokkeri На самом деле у меня нет контроля над потоком для чтения байтов, последовательно записанных в основной файл. Есть ли у вас идеи, как я могу отслеживать его и последовательно записывать во вторичный файл, чтобы содержимое файла было правильным? Или что вы предлагаете? Следует ли мне читать основной файл после того, как он полностью записан? или я могу прочитать это, пока идет запись?

Harisingh Rajput 03.05.2018 15:19

@HarisinghRajput Зависит от основной цели. Просто скопировать файлы или скопировать файлы наиболее эффективным способом ... Самый простой способ - сначала полностью скопировать первичный файл, а затем скопировать его во вторичные места. Вопрос; в чем причина "основного" местоположения? Не могли бы вы просто скопировать исходный файл в 4 одинаковых места?

Jokkeri 04.05.2018 07:19

@Jokkeri Да, теперь мы пытаемся использовать самый простой способ - сначала полностью скопировать первичный файл, а затем скопировать его во вторичные места, что является прямым способом. И он работает нормально. Не могли бы вы просто скопировать исходный файл в 4 одинаковых места? Если мы пойдем с этим подходом, то это ухудшит нашу производительность, потому что мы должны дождаться завершения записи 4 местоположений. Наша цель первичного местоположения состоит в том, что сначала мы должны дождаться загрузки только первичного местоположения, а запись вторичных местоположений должна выполняться асинхронно в фоновом режиме, поэтому мы передаем этот процесс потокам.

Harisingh Rajput 04.05.2018 08:11

@Jokkeri Как только загрузка файла первичного местоположения завершится, мы дадим ответ об успешном завершении, независимо от того, завершена или ожидает загрузка файла вторичного местоположения. Думаю, теперь вам понятнее

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

Ответы 1

Ответ принят как подходящий

Вот пример, который я не рекомендую использовать «как есть» - его намерение состоит в том, чтобы действовать как доказательство концепции. В примере сначала выполняется первичный процесс, чтобы достичь максимальной производительности на этом этапе. Затем вторичные операции выполняются каждый в собственном параллельном потоке.

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.UnknownHostException;

import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;
import jcifs.smb.SmbFileInputStream;
import jcifs.smb.SmbFileOutputStream;

public class testSmb {

    static boolean append = true;
    static int threadCount = 0;

    static int bufferSize = 2048;

    static NtlmPasswordAuthentication auth;

    static File localFile;

    static SmbFile primarySmbFile;
    static BufferedInputStream input;
    static SmbFileOutputStream output;

    static SmbFile secondary1SmbFile;
    static BufferedInputStream sec1Input;
    static SmbFileOutputStream sec1Output;

    static SmbFile secondary2SmbFile;
    static BufferedInputStream sec2Input;
    static SmbFileOutputStream sec2Output;

    static SmbFile secondary3SmbFile;
    static BufferedInputStream sec3Input;
    static SmbFileOutputStream sec3Output;

    public static Object lock = new Object();

    public static void main(String... args) throws IOException {
        System.out.println("Main thread Started");
        init();
        write(input, output);
        writeInThread(sec1Input, sec1Output);
        writeInThread(sec2Input, sec2Output);
        writeInThread(sec3Input, sec3Output);

        System.out.println("Main thread Finished");
    }

    public static void init() throws MalformedURLException,
            FileNotFoundException, SmbException, UnknownHostException {

        localFile = new File("c:\\temp\\myFile.txt");
        if (localFile.length() > 20971520l) {
            bufferSize = 131072;
        }

        String server = "myServer";
        String username = "myUser";
        String password = "myPass";
        String path = "myPath";
        auth = new NtlmPasswordAuthentication(server, username, password);

        input = new BufferedInputStream(new FileInputStream(localFile));
        primarySmbFile = new SmbFile("smb://" + server + "/" + path
                + "/primary.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        output = new SmbFileOutputStream(primarySmbFile, append);
        if (!primarySmbFile.exists()) {
            primarySmbFile.createNewFile();
        }

        sec1Input = new BufferedInputStream(new SmbFileInputStream(new SmbFile(
                primarySmbFile, primarySmbFile.getName())));
        secondary1SmbFile = new SmbFile("smb://" + server + "/" + path
                + "/secondary1.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        sec1Output = new SmbFileOutputStream(secondary1SmbFile, append);
        if (!secondary1SmbFile.exists()) {
            secondary1SmbFile.createNewFile();
        }

        sec2Input = new BufferedInputStream(new SmbFileInputStream(new SmbFile(
                primarySmbFile, primarySmbFile.getName())));
        secondary2SmbFile = new SmbFile("smb://" + server + "/" + path
                + "/secondary2.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        sec2Output = new SmbFileOutputStream(secondary2SmbFile, append);
        if (!secondary2SmbFile.exists()) {
            secondary2SmbFile.createNewFile();
        }

        sec3Input = new BufferedInputStream(new SmbFileInputStream(new SmbFile(
                primarySmbFile, primarySmbFile.getName())));
        secondary3SmbFile = new SmbFile("smb://" + server + "/" + path
                + "/secondary3.txt", auth, SmbFile.FILE_SHARE_READ
                | SmbFile.FILE_SHARE_WRITE | SmbFile.FILE_SHARE_DELETE);
        sec3Output = new SmbFileOutputStream(secondary3SmbFile, append);
        if (!secondary3SmbFile.exists()) {
            secondary3SmbFile.createNewFile();
        }

    }

    public static void write(BufferedInputStream bufferedInputStream,
            SmbFileOutputStream smbFileOutputStream) throws IOException {

        byte[] buffer = new byte[bufferSize];
        int len = 0;

        try {

            while ((len = bufferedInputStream.read(buffer)) > 0) {
                synchronized (lock) {
                    System.out.println("'" + Thread.currentThread().getName()
                            + "' writing " + bufferSize + "bytes");
                    smbFileOutputStream.write(buffer, 0, len);
                    smbFileOutputStream.flush();
                }
            }

        } catch (IOException e) {
            throw e;
        } finally {
            try {
                bufferedInputStream.close();
            } catch (Exception e) {
            }

            try {
                smbFileOutputStream.flush();
                smbFileOutputStream.close();
            } catch (Exception e) {
            }
        }

    }

    public static void writeInThread(
            final BufferedInputStream bufferedInputStream,
            final SmbFileOutputStream smbFileOutputStream) {
        threadCount++;

        new Thread("Secondary thread " + threadCount) {
            public void run() {
                System.out.println(Thread.currentThread().getName()
                        + ": started");
                try {
                    write(bufferedInputStream, smbFileOutputStream);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                        + ": finished");
            }
        }.start();

    }
}

Спасибо, что поделились программой. Он работает нормально, поскольку мы обсуждали, что он начинает загружать файл во второстепенные места после завершения загрузки основного файла. Теперь у меня вопрос, что все второстепенные локации записываются параллельно или одно за другим последовательно?

Harisingh Rajput 04.05.2018 12:31

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

Harisingh Rajput 04.05.2018 12:38

Отредактировал пример, чтобы сделать его параллельным

Jokkeri 04.05.2018 12:48

jcifs.smb.SmbException: недействительный дескриптор.

Harisingh Rajput 04.05.2018 13:35
При параллельной записи иногда это удается, а иногда выдает ошибку ниже в случае большого размера файла около 200 МБ. в jcifs.smb.SmbTransport.checkStatus (SmbTransport.java:563) в jcifs.smb.SmbTransport.send (SmbTransport.java:663) в jcifs.smb.SmbSession.send (SmbSession.java:238s.send (SmbSession.java:238s) в jcifsession. .SmbTree.send (SmbTree.java:119) в jcifs.smb.SmbFile.send (SmbFile.java:775) в jcifs.smb.SmbFileInputStream.readDirect (SmbFileInputStream.j‌ ava: 181)
Harisingh Rajput 04.05.2018 13:37

@HarisinghRajput Как насчет этого (отредактировал пример), добавил некоторую синхронизацию и не использовал повторно объект primarySmbFile при создании inputStream

Jokkeri 04.05.2018 14:23

После добавления синхронизации теперь все работает нормально. Я ценю вашу помощь. Большое спасибо за вашу постоянную поддержку.

Harisingh Rajput 04.05.2018 16:06

Приятно слышать, если ответ решит вашу проблему, примите его

Jokkeri 07.05.2018 06:38

На самом деле я поднял этот вопрос, как указано в заголовке Загрузка файла в основное место и одновременное чтение и запись одного и того же файла в несколько дополнительных мест. Это проблема с одновременным чтением и записью в основной файл. И мы попробовали другой подход: сначала полностью загрузить на первичный, а затем скопировать его во вторичные места, что является последовательным подходом. Поэтому я думаю, что ваш ответ дает мне другой подход, но не связан с заданным вопросом.

Harisingh Rajput 07.05.2018 07:39

Я ценю вашу помощь. Но было бы хорошо, если бы вы могли упомянуть здесь, что в то же время чтение / запись невозможно, и я должен следовать последовательному подходу (например, первый основной файл полностью загружен, затем только чтение из основного и запись в несколько дополнительных файлов). Что ты говоришь?

Harisingh Rajput 07.05.2018 07:43

это очень медленно .. можем ли мы сделать быстрее? Я обновил размер буфера, но он все еще медленный

Vijaysinh Parmar 11.11.2020 13:38

Попробуйте этот stackoverflow.com/questions/10533653/…. В частности, свойства jcifs.resolveOrder и jcifs.smb.client.dfs.disabled. Программно вы можете использовать такие, как этот jcifs.Config.setProperty("jcifs.resolveOrder", "DNS");

Jokkeri 13.11.2020 13:51

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