Получение InputStream для чтения более одного раза, независимо от markSupported () - PullRequest
10 голосов
/ 12 октября 2011

Мне нужно многократно использовать java.io.InputStream несколько раз, и я подумал, что следующий код будет работать, но он работает только в первый раз.

код


public class Clazz
{
  private java.io.InputStream dbInputStream, firstDBInputStream;
  private ArrayTable db;

  public Clazz(java.io.InputStream defDB)
  {
    this.firstDBInputStream = defDB;
    this.dbInputStream = defDB;
    if (db == null)
      throw new java.io.FileNotFoundException("Could not find the database at " + db);
    if (dbInputStream.markSupported())
      dbInputStream.mark(Integer.MAX_VALUE);
    loadDatabaseToArrayTable();
  }

  public final void loadDatabaseToArrayTable() throws java.io.IOException
  {
    this.dbInputStream = firstDBInputStream;
    if (dbInputStream.markSupported())
      dbInputStream.reset();

    java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
    String CSV = "";
    for (int i = 0; fileScanner.hasNextLine(); i++)
      CSV += fileScanner.nextLine() + "\n";
    db = ArrayTable.createArrayTableFromCSV(CSV);
  }

  public void reloadDatabase()//A method called by the UI
  {
    try
    {
      loadDatabaseToArrayTable();
    }
    catch (Throwable t)
    {
      //Alert the user that an error has occurred
    }
  }
}

Обратите внимание, что ArrayTable - мой класс, который использует массивы для предоставления интерфейса для работы с таблицами.

Вопрос


В этой программе база данных отображается непосредственно пользователю сразу после вызова метода reloadDatabase(), и поэтому любое решение, включающее сохранение первоначального чтения в объекте в памяти, бесполезно, так как это НЕ будет обновлять данные ( Думайте об этом как о браузере: когда вы нажимаете «Обновить», вы хотите, чтобы он снова получал информацию, а не просто отображал информацию, полученную в первый раз). Как я могу прочитать java.io.InputStream более одного раза?

Ответы [ 2 ]

8 голосов
/ 12 октября 2011

Вы не можете обязательно прочитать InputStream более одного раза.Некоторые реализации поддерживают это, некоторые нет.Что вы делаете, это проверяете метод markSupported, который действительно является индикатором, если вы можете прочитать один и тот же поток дважды, но тогда вы игнорируете результат.Вы должны вызвать этот метод, чтобы увидеть, можете ли вы прочитать поток дважды, а если не можете, принять другие меры.

Редактировать (в ответ на комментарий): Когда я писал свой ответ, мой "другой"договоренности "должен был получить свежий InputStream.Однако когда я читаю в ваших комментариях к вашему вопросу о том, что вы хотите сделать, я не уверен, что это возможно.Для основ операции вы, вероятно, захотите RandomAccessFile (по крайней мере, это будет мое первое предположение, и если это сработает, это будет проще всего) - однако у вас будут проблемы с доступом к файлам.У вас есть приложение, активно пишущее в файл, и другое чтение этого файла, у вас будут проблемы - какие именно проблемы будут зависеть от ОС, поэтому любое решение потребует дополнительного тестирования.Я предлагаю отдельный вопрос о SO, который затрагивает этот вопрос, и кто-то, кто попробовал это, может дать вам больше понимания.

2 голосов
/ 12 октября 2011

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

public Clazz(java.io.InputStream defDB)
  {
    firstDBInputStream = defDB.markSupported()?defDB:new BufferedInputStream(defDB);
      //BufferedInputStream supports marking
    firstDBInputStream.mark(500000);//avoid IOException on first reset
  }

public final void loadDatabaseToArrayTable() throws java.io.IOException
  {
    this.dbInputStream = firstDBInputStream;

    dbInputStream.reset();
    dbInputStream.mark(500000);//or however long the data is

    java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
    StringBuilder CSV = "";//StringBuilder is more efficient in a loop
    while(fileScanner.hasNextLine())
      CSV.append(fileScanner.nextLine()).append("\n");
    db = ArrayTable.createArrayTableFromCSV(CSV.toString());
  }

однако вы можете вместо этого сохранить копию оригинального ArrayTable и скопировать ее, когда вам нужно (или даже созданную строку для ее восстановления)

этот код создает строку и кэширует ее, чтобы вы могли безопасно отбрасывать входные потоки и просто использовать readCSV для построения ArrayTable

  private String readCSV=null;
  public final void loadDatabaseToArrayTable() throws java.io.IOException
  {
    if(readCSV==null){

        this.dbInputStream = firstDBInputStream;


        java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
        StringBuilder CSV = "";//StringBuilder is more efficient in a loop
        while(fileScanner.hasNextLine())
          CSV.append(fileScanner.nextLine()).append("\n");

        readCSV=CSV.toString();
        fileScanner.close();

    }
    db = ArrayTable.createArrayTableFromCSV(readCSV);
  }

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

...