Получение InputStream для чтения более одного раза, независимо от markSupported()

Мне нужно иметь возможность повторно использовать 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 ответа

Решение

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

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

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

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

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

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