如何更新openFileOutput创建的文件

时间:2011-07-27 19:15:50

标签: java android file

我正在构建一个应用程序,用户将随着时间的推移生成数据,如果他/她有互联网连接,则将其传输到Web。但是,如果他没有网络访问权限,我需要将这些数据存储在手机中,直到用户恢复访问权限,此时我需要恢复要传输的数据。但是,我正面临很多麻烦,如下所示。

注意:在此之前,我正在使用本地java创建的文件,因为我知道没有其他方法可以在设备上保存/恢复此数据。如果您碰巧知道从设备中存储/访问此数据的任何其他方式,请随时在此处发表评论。

仅供参考,

  • phantoms是一个ArrayList,包含具有我需要的数据的对象 商店,
  • Arquivador是我用来使我的数据持久并恢复它的类,
  • Funcionario是包含程序生成的数据的类(只有几个字符串和数字)

我可以通过下面的代码在我的Activity:

上将文件写入文件系统
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.");
    }
}

您会注意到我将数据添加到两个步骤中的持久性,第一个Object和其余部分。这是我在StackOverflow中看到on this post的一个想法,允许将数据附加到Java生成的文件中。我对这段代码没有任何问题,它完美无缺。

稍后,回到我的Activity,检测到互联网连接,我尝试恢复保存在磁盘上的文件:

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()似乎工作得很好。我甚至可以将read Object转换为Funcionario类并读取其数据。

我使用removeObjectFromFile()时出现问题。我们的想法是创建一个临时文件来存储“dados.jlog”文件中的对象,而不是已经加载到主程序中的文件,然后一旦创建了这个临时文件,就应该删除文件“dados.jlog”。应重命名临时文件以替换它。

我在这里发现的第一件事就是ois.readobject()不断抛出EOFException。虽然这是有道理的,但我在互联网上阅读的教程没有提到这个错误。实际上,它们的代码表明当readObject()方法到达EOF时,它会返回对null的引用,但是这个类会抛出此EOFException。我在代码中处理了这个异常 - 虽然我不确定这是否是正确的方法。

我觉得奇怪的另一件事是这个代码无法识别它不应该复制的对象。当我将从文件读取的对象与作为参数接收的对象进行比较时,无论我尝试什么(==,equals()等),它们看起来都是编译器的不同对象。 Funcionario类是serializable有一个serialversionUID,因此从文件中读取的对象应该与我存储的对象相同。更糟糕的是,这两个被比较的对象是从同一个文件中读取的。它们应该是相同的,对吧?

创建临时文件后,我尝试删除原始文件并重命名临时文件。虽然这似乎有效,但是一旦removeObjectFromFile()第一次结束,程序就无法再次从文件“dados.jlog”中读取数据。我无法从文件中读取剩余数据,程序进入无限循环 - 因为第一个对象永远不会从文件列表中删除。

请通知此事。

1 个答案:

答案 0 :(得分:3)

我个人使用SQLLite数据库。将每个对象存储在数据库中的一行中。成功传输后,您可以从数据库中删除该行。

您甚至可以重复使用已经完成的大部分代码。到达目的地的最简单方法是为每个对象使用单独的文件,并仅在数据库中存储对象的文件名。然后,您可以遍历数据库中的行。每次将对象传输到服务器时,只需从数据库中删除该行(并从文件系统中删除该文件!)。数据库中没有行意味着没有剩余的对象可以传输。