Как мне обновить файл, созданный openFileOutput - PullRequest
3 голосов
/ 27 июля 2011

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

Примечание: прежде всего я использую локальный файл, созданный Java, потому что я не знаю другого способа сохранить / восстановить эти данные на устройстве. Если вам известен какой-либо другой способ хранения / доступа к этим данным из устройства, пожалуйста, не стесняйтесь комментировать здесь.

Только для справки,

  • фантомы - это ArrayList, содержащий объекты с данными, которые мне нужны магазин,
  • Arquivador - это класс, который я использую, чтобы сделать мои данные постоянными и восстановить их,
  • Funcionario - это класс с данными, сгенерированными программой (всего несколько строк и чисел)

Я могу записать файл в файловую систему с помощью приведенного ниже кода в моей Активности:

try {
    arq = new Arquivador();
    arq.addFirstObjectInFile(
            openFileOutput("dados.jlog", MODE_WORLD_WRITEABLE),
            phantoms.get(0));
    phantoms.remove(phantoms.get(0));
    for (Funcionario func : phantoms) {
        arq.addObjectInFile(openFileOutput("dados.jlog", MODE_APPEND),
                func);
    }
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
}

Вот код внутри Arquivador, который добавляет данные в файл:

public void addObjectInFile(FileOutputStream arquivo,
        Object objetoAAdicionar) {
    try {
        ObjectOutputStream aoos = new ObjectOutputStream(arquivo);
        aoos.writeObject(objetoAAdicionar);
        aoos.close();
    } catch (IOException ioe) {
        Log.d(TAG_NAME, "Erro no Appendable OOS.");
    }
}

public void addFirstObjectInFile(FileOutputStream arquivo,
        Object objetoAAdicionar) {
    try {
        AppendableObjectOutputStream aoos = new AppendableObjectOutputStream(
                arquivo);
        aoos.writeObject(objetoAAdicionar);
        aoos.close();
    } catch (IOException ioe) {
        Log.d(TAG_NAME, "Erro no Appendable OOS.");
    }
}

Вы заметите, что я добавляю данные в постоянство в 2 этапа: первый объект и остальные. Эту идею я увидел в этом посте здесь, в StackOverflow, чтобы разрешить добавление данных в файл, сгенерированный Java. У меня нет проблем с этим кодом, он работает отлично.

Позже, вернувшись к моей Активности, обнаруживается интернет-соединение, и я пытаюсь восстановить файл, сохраненный на диске:

phantoms = new ArrayList<Funcionario>();
Object obj = arq.readObjectFromFile(openFileInput("dados.jlog"));
Funcionario func = null;
if (obj instanceof Funcionario) {
    func = (Funcionario) obj;
}
while (func != null) {
    phantoms.add(func);
    arq.removeObjectFromFile(openFileInput("dados.jlog"), func,
            getApplicationContext());
    func = (Funcionario) arq
            .readObjectFromFile(openFileInput("dados.jlog"));
}

Первоначальная идея состояла в том, чтобы читать 1 объект за раз, затем пытаться передать его и, в случае успеха, удалить объект из файла (чтобы он не был передан повторно). Тем не менее, у меня было слишком много сообщений об ошибках с этим. Вместо этого я решил загрузить все объекты, один за другим, чтобы увидеть, где моя проблема была более ясной.

Вернуться к классу Arquivador:

public Object readObjectFromFile(FileInputStream arquivo) {
    Object retorno = null;
    if (arquivo.equals(null)) {
        Log.e(TAG_NAME, "FIS is null!");
    }
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(arquivo);
        retorno = ois.readObject();
    } catch (IOException ioex) {
    } catch (ClassNotFoundException e) {
    } finally {
        try {
            if (ois != null) ois.close();
        } catch (IOException e) {
        }
    }
    return retorno;
}

public void removeObjectFromFile(FileInputStream arqPrincipal,
        Object objetoARemover, Context contexto) {
    try {
        // Construct the new file that will later be renamed to the original
        // filename.
        ObjectOutputStream oos = new ObjectOutputStream(
                contexto.openFileOutput("dados.jlog.temp",
                        contexto.MODE_APPEND));
        ObjectInputStream ois = new ObjectInputStream(arqPrincipal);
        Object obj = null;
        // Read from the original file and write to the new
        // unless content matches data to be removed.
        try {
            while ((obj = ois.readObject()) != null) {
                if (!(objetoARemover.equals(obj))) {
                    oos.writeObject(obj);
                    oos.flush();
                }
            }
        } catch (EOFException eof) {
        } finally {
            oos.close();
            ois.close();
            // Delete the original file
            File aDeletar = contexto.getFileStreamPath("dados.jlog");
            File aRenomear = contexto.getFileStreamPath("dados.jlog.tmp");
            if (!aDeletar.delete()) {
                return;
            } else {
                // Rename the new file to the filename the original file
                // had.
                if (!aRenomear.renameTo(aDeletar)) Log.d(TAG_NAME,
                        "Error renaming file");
                else Log.d(TAG_NAME, "Renaming successful");
            }
        }
    } catch (FileNotFoundException ex) {
        ex.printStackTrace();
        Log.d(TAG_NAME, "Arquivo não encontrado");
    } catch (IOException ex) {
        ex.printStackTrace();
        Log.d(TAG_NAME, "Erro de entrada/saída");
    } catch (ClassNotFoundException e) {
        Log.d(TAG_NAME, "Classe Não Encontrada.");
    }
}

Метод readObjectFromFile(), кажется, работает просто отлично. Я даже могу преобразовать прочитанный объект в Funcionario класс и прочитать его данные.

Мои проблемы появляются при использовании removeObjectFromFile(). Идея состоит в том, чтобы создать временный файл для хранения объектов из файла «dados.jlog», отличного от того, который уже был загружен в основную программу, а затем, после создания этого временного файла, файл «dados.jlog» должен быть удален и временный файл должен быть переименован, чтобы заменить его.

Первое, что я обнаружил здесь странным, это то, что ois.readobject() продолжает выдавать исключение EOFException. Хотя это имеет смысл, учебник, который я прочитал в Интернете, не упоминает об этой ошибке. Фактически, их код указывает, что когда метод readObject () достигает EOF, он возвращает ссылку на ноль, но вместо этого этот класс выдает это исключение EOFException. Я обработал это исключение в коде - хотя я не уверен, что это будет правильным способом.

Другая вещь, которую я нахожу странной, это то, что этот код не может распознать объект, который он НЕ должен копировать. Когда я сравниваю объект, прочитанный из файла, с объектом, полученным в качестве аргумента, независимо от того, что я пытаюсь (==, equals () и т. Д.), Они кажутся компилятору различными объектами. Класс Funcionario является сериализуемым и имеет serialversionUID, поэтому объект, считываемый из файла, должен быть идентичным тому, который я сохранил. Хуже того, эти 2 сравниваемых объекта считываются из одного и того же файла. Они должны быть одинаковыми, верно?

После создания временного файла я пытаюсь удалить исходный файл и переименовать временный файл. Хотя кажется, что это работает, после того как removeObjectFromFile () завершает работу в первый раз, программа не может снова прочитать данные из файла "dados.jlog". Я не могу прочитать оставшиеся данные из файла, и программа входит в бесконечный цикл - поскольку 1-й объект никогда не удаляется из списка в файле.

Пожалуйста, просветите меня этим вопросом.

1 Ответ

3 голосов
/ 27 июля 2011

Лично я бы использовал базу данных SQLLite.Храните каждый объект подряд в базе данных.После успешной передачи вы можете удалить строку из базы данных.

Вы можете даже использовать большую часть своего кода, который вы уже сделали.Самый простой способ добраться туда, где вы находитесь, это использовать отдельный файл для каждого объекта и хранить только имя файла объекта в базе данных.Затем вы можете перебирать строки в базе данных.Каждый раз, когда вы передаете объект на сервер, просто удаляйте эту строку из базы данных (и удаляйте файл из файловой системы!).Отсутствие строк в базе данных означает, что не осталось объектов для передачи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...