簡體   English   中英

為什么我的手機應用程序無法打開它存儲在房間數據庫中的文件?

[英]Why can't my phone app open a file it stored in a Room Database?

問題:我的 Android 手機應用程序可以打開存儲在Android Room預填充SQLite數據庫中的各種文件類型,但無法打開應用程序本身添加到預填充數據庫中的文件(除非它可以打開 .txt 文件)。 我相信問題可能與我如何編碼所選文件的復制和轉換為byte[]數據有關。 該應用程序是基於 Java 的,我之前在桌面應用程序中使用 Java 完成了此操作,所以我似乎無法找到問題所在。 也許這是一個許可問題,我只是不確定,站在外面的人可能會看到我看不到的東西。

我嘗試過的:由於該應用程序可以從數據庫成功打開各種現有的預填充文件,因此我專注於並逐步介紹了將文件寫入數據庫的方法。 我沒有收到任何錯誤。 我懷疑這可能只是小問題,因為我似乎看不到它。

我正在嘗試做的事情:我正在嘗試將此應用程序的桌面版本模擬為 Android 手機版本。 我知道不推薦或不常用的做法是將文件填充到數據庫,但此應用程序需要能夠讀取和寫入文件到支持它的數據庫。 這將是各種文件類型,如桌面版本(例如,圖片、文檔、音頻、視頻等)。 但是,正如我上面所說,.txt 文件似乎沒有問題。 用戶可以將存儲在手機上的文件選擇到一個表中,該表將fileNamefilePath捕獲到TableLayoutTableRow 下面是涉及的方法。 計划是在我開始工作后重構功能:

捕獲每一行的完整路徑和文件名- 使用捕獲的文件路徑轉換為byte[]來存儲數據。 文件名和文件字節數據存儲在 Files 表中,例如 Files(fileName, fileData(byte[]))。 每個文件都添加到該方法返回的ArrayList<Files>

public static List<Files> captureNoteFiles(TableLayout table){
    List<Files> noteFiles = new ArrayList<>();
    int i = table.getChildCount();
    if(i>1){
        for (int itr = 1; itr<i; itr++) { // iterating through indexes
            TableRow tr = (TableRow) table.getChildAt(itr);
            TextView tv = (TextView) tr.getChildAt(1); // 1 is the file path position
            File f = new File(tv.getText().toString());
            String n = f.getName();

            try {
                FileInputStream fis = new FileInputStream(f.getPath());
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                byte[] buf = new byte[1024];
                for (int read; (read = fis.read(buf)) != -1; ) {
                    bos.write(buf, 0, read);
                }
                fis.close();

                noteFiles.add(new Files(0, n, bos.toByteArray()));
            } catch (Exception e) {
                e.printStackTrace();
                Log.d("Input File", e.toString());
            }
        }
    }
    return noteFiles;
}

ArrayList 的迭代- ArrayList<Files>被迭代並填充到 Files 表和 ID 捕獲以將這些文件與特定的參考注釋相關聯。

public static void addNewNoteFiles(int noteID, List<Files> nf){
    if(nf.size()>0) {
        for (Files f : nf) {
            long id = rdb.getFilesDao().addFile(f);
            rdb.getFilesByNoteDao().insert(new FilesByNote(noteID, (int) id));
        }
    }
}

文件實體

@Entity(tableName = "Files")
public class Files implements Parcelable {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "FileID")
    private int fileID;

    @ColumnInfo(name = "FileName")
    private String fileName;

    @TypeConverters(FileTypeConverter.class)
    @ColumnInfo(name = "FileData", typeAffinity = ColumnInfo.TEXT)
    private byte[] fileData;

    @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
    public Files(int fileID, String fileName, byte[] fileData){
        this.fileID = fileID;
        this.fileName = fileName;
        this.fileData = fileData;
    }
}

首先,您假設插入按以下方式工作:-

        long id = rdb.getFilesDao().addFile(f);
        rdb.getFilesByNoteDao().insert(new FilesByNote(noteID, (int) id));

如果沒有插入行怎么辦? 並返回-1的id?

所以我建議將 getter 添加到Files類,例如:-

public int getFileID() {
    return fileID;
}

public String getFileName() {
    return fileName;
}

public byte[] getFileData() {
    return fileData;
}

然后將以下內容添加到FilesDao 中:-

@Query("SELECT coalesce(length(FileData)) FROM Files WHERE FileID=:fileId")
abstract long getFilesDataLength(long fileId);

然后將addNewNoteFiles修改為:-

public static void addNewNoteFiles(int noteID, List<Files> nf){

    final String TAG = "ADDNEWNOTE";
    if(nf.size()>0) {
        for (Files f : nf) {
            long id = rdb.getFilesDao().addFile(f);
            if (id > 0) {
                long lengthOfFileData = rdb.getFilesDao().getFilesDataLength(id);
                Log.d(TAG,
                        "Inserted File = " + f.getFileName() +
                                " DataLength = " + f.getFileData().length +
                                " ID = " + f.getFileID() +
                                " Length of Stored Data = " + lengthOfFileData);
                if (f.getFileData().length != lengthOfFileData) {
                    Log.d(TAG,"WARNING FileData length MISMATCH for File = " + f.getFileName() + "\n\t Expected " + f.getFileData().length + " Found " + lengthOfFileData);
                }
                rdb.getFilesByNoteDao().insert(new FilesByNote(noteID, (int) id));

            } else {
                Log.d(TAG,"NOT INSERTED File = " + f.getFileName());
            }
        }
    }
}

運行並查看日志。 所有文件都插入了嗎? 長度匹配嗎? 長度是否符合預期(如果全部為 0 長度,或者一些長度,那么在構建 ByteArrayOutputStream 時顯然有些問題)

您可能希望為插入 FilesByNote 添加類似的內容,即讓插入 Dao 返回一個 long(它返回 rowid)並檢查該值是否 > 0。

  • 您可能想知道 rowid 是什么。 嗯,它是一個通常隱藏的列,可能是隱藏的,因為 FilesByNotes 是一個關聯表映射(關聯)Note(s) 與文件,因此具有復合主鍵 NoteId 和 FileId,它不是 rowid 的別名,所以rowid 將被隱藏。 但是,如果沒有插入行,該值將自動生成或 -1。
    • 除了使用 WITHOUT ROWID 定義的表外,所有表都有一個 rowid 列。 Room 不允許定義 WITHOUT ROWID 表。

如果它大於 0,您就不會關心該值,只要它大於 0 並因此插入了一行。

以上可能有助於確定插入數據時遇到的任何問題。 如果沒有找到,那么問題出在其他地方。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM