【问题标题】:Uploading a SQLite database file to an S3 bucket将 SQLite 数据库文件上传到 S3 存储桶
【发布时间】:2021-06-20 19:00:58
【问题描述】:

我目前正在 Android Studio 中开发一个实现 AWS S3 的项目。 S3 的用途是在其上上传/存储我的本地 SQLite 数据库文件,以便我可以下载并在命令中使用它。我意识到这绝不是在 S3 中使用数据库的最佳方式。

我可以在我的 S3 存储桶中上传和下载文件。但是由于某种原因,根据 logcat,数据库文件已损坏。 SQLite 数据库文件在下载时存储在设备的数据库文件夹中。

这是实现的代码:

public void uploadFile(String fileName) {
    File exampleFile = new File(getApplicationContext().getDatabasePath("Login.db").getPath());

    try {
        BufferedWriter writer = new BufferedWriter(new FileWriter(exampleFile));
        writer.append("Example file contents");
        writer.close();
    } catch (Exception exception) {
        Log.e("MyAmplifyApp", "Upload failed", exception);
    }

    Amplify.Storage.uploadFile(
        fileName,
        exampleFile,
        result -> Log.i("MyAmplifyApp", "Successfully uploaded: " + result.getKey()),
        storageFailure -> Log.e("MyAmplifyApp", "Upload failed", storageFailure)
    );
}

public void downloadFile() {
    Amplify.Storage.downloadFile(
        "Login.db",
        new File(getApplicationContext().getDatabasePath("Login.db") + ""),
        result -> Log.i("MyAmplifyApp", "Successfully downloaded: " + result.getFile().getName()),
        error -> Log.e("MyAmplifyApp",  "Download Failure", error)
    );
}

我正在寻找有关此问题的一些见解。我只是不确定是什么导致了文件损坏。我在想它可能是文件路径,但我相信导航正确。

【问题讨论】:

  • S3 不是数据库。为什么不使用适当的数据库,例如 DynamoDB?
  • 为什么要在上传文件前写入数据?
  • 您使用的是什么记录模式? WAL 还是期刊?如果 WAL 确保数据库已完全设置检查点(关闭数据库)?如果不是并且 WAL 文件 Login.db-wal 不为空,那么您需要复制 Login.db-wal 和可能的 Login.db-shm 文件以及 Login.db。见sqlite.org/wal.html。由于 Android 9 WAL 是默认模式,请参阅source.android.com/devices/tech/perf/compatibility-wal
  • @Marcin 我 100% 同意你的看法。这个项目是一个类项目,我们已经开始使用 SQLite。使用这种方式是完全低效的,但在建议 DynamoDB 或 aurora 时遇到了摩擦。
  • 我相信它正在使用 Journal Pragma。我检查了 logcat,它吐出了错误:E/SQLiteLog: (26) file is not a database in "PRAGMA journal_mode" E/SQLiteDatabase: Database corruption detected in open() android.database.sqlite.SQLiteDatabaseCorruptException: file is not a database (code 26 SQLITE_NOTADB): , while compiling: PRAGMA journal_mode

标签: amazon-web-services android-studio amazon-s3 android-sqlite android-device-monitor


【解决方案1】:

我怀疑您的问题是该文件实际上已损坏,并且可能是由于您使用 writer.append("Example file contents"); 并保存了一个仅包含该文件的文件。

您也许可以添加代码在上传文件之前和下载文件之后进行一些检查。

以下是这样的代码的 sn-p(在这种情况下,检查资产是否是有效的 sqlite 文件,它可能有点过头了):-

/**
 * DBHEADER
 * The the header string, the first 16 bytes, of the SQLite file
 *  This should never be changed.
 */
private static final String DBHEADER = "SQLite format 3\u0000"; // SQLite File header first 16 bytes

/**
 * Constants that represent the various stages of the copy
 */
private static final int
        STAGEOPENINGASSETFILE = 0,
        STAGEOPENINGDATABASEFILE = 1,
        STAGECOPYING = 3,
        STAGEFLUSH = 4,
        STAGECLOSEDATABSE = 5,
        STAGECLOSEASSET = 6,
        STAGEALLDONE = 100
                ;
/**
 * Constants for message codes
 */
private static final int
        MSGCODE_EXTENDASSETFILE_ADDEDSUBDIRECTORY = 20,
        MSGCODE_EXTEANDASSETFILE_EXTENDEDFILENAME = 21,
        MSGCODE_CHECKASSETFILEVALIDTY_OPENEDASSET = 30,
        MSGCODE_CHECKASSETFILEVALIDITY_OPENFILED = 31,
        MSGCODE_CHECKASSETFILEVALIDITY_NOTSQLITEFILE = 32,
        MSGCODE_CHECKASSETFILEVALIDITY_VALIDSQLITEFILE = 33,
        MSGCODE_COPY_FAILED = 40,
        MSGCODE_COPY_OK = 41
                ;

/**
 * The default buffer size, can be changed
 */
private static final int DEFAULTBUFFERSIZE = 1024 * 32; // 32k buffer

....


/**
 * Check that the asset file to be copied exists and optionally is a valid
 * SQLite file
 * @param cntxt                     The Context
 * @param extendedAssetFilename     The asset file name including subdirectories
 * @param showstacktrace            true id to show the stack-trace if an exception as trapped
 * @param checkheader               true if the SQLite file header should be checked
 * @return                          true if the checks are ok
 */
public static boolean checkAssetFileValidity(Context cntxt, String extendedAssetFilename, boolean showstacktrace, boolean checkheader) {
    boolean rv = true;
    InputStream is;
    try {
        is = cntxt.getAssets().open(extendedAssetFilename);
        messages.add(
                new Msg(
                        MSGCODE_CHECKASSETFILEVALIDTY_OPENEDASSET,
                        Msg.MESSAGETYPE_INFORMATION,
                        "Successfully Opened asset file " + extendedAssetFilename
                )
        );
        if (checkheader) {
            byte[] fileheader = new byte[DBHEADER.length()];
            is.read(fileheader,0,fileheader.length);
            if (!(new String(fileheader)).equals(DBHEADER)) {
                messages.add(
                        new Msg(
                                MSGCODE_CHECKASSETFILEVALIDITY_NOTSQLITEFILE,
                                Msg.MESSAGETYPE_ERROR,
                                "Asset file " +
                                        extendedAssetFilename +
                                        " is NOT an SQlite Database, instead found " + (new String(fileheader))
                        )
                );
                is.close();
                return false;
            } else {
                messages.add(
                        new Msg(
                        MSGCODE_CHECKASSETFILEVALIDITY_VALIDSQLITEFILE,
                                Msg.MESSAGETYPE_INFORMATION,
                                "Successfully validated asset file " + extendedAssetFilename +
                                        " . It has a valid SQLite Header."
                        )
                );
            }
        }
        is.close();
    } catch (IOException e) {
        messages.add(
                new Msg(
                        MSGCODE_CHECKASSETFILEVALIDITY_OPENFILED,
                        Msg.MESSAGETYPE_ERROR,
                        "Unable to open asset " + extendedAssetFilename + "."
                )
        );
        if (showstacktrace) {
            e.printStackTrace();
        }
        return false;
    }
    return rv;
}
  • 没有包含 Msg 类和相关方法,它们仅用于记录消息。如果您想添加它们,请大声喊叫。

主要是检查标题。

【讨论】:

  • 上帝保佑先生,非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2018-04-25
  • 2018-06-08
  • 1970-01-01
  • 2018-03-25
  • 2018-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多