简体   繁体   English

为什么我的手机应用程序无法打开它存储在房间数据库中的文件?

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

Problem: My Android phone app can open various file types stored in an Android Room pre-populated SQLite database but it cannot open files the app itself has added to the pre-populated database (except it can open .txt files).问题:我的 Android 手机应用程序可以打开存储在Android Room预填充SQLite数据库中的各种文件类型,但无法打开应用程序本身添加到预填充数据库中的文件(除非它可以打开 .txt 文件)。 I believe the issue is probably with how the I coded the copying and conversion of a selected file to byte[] data.我相信问题可能与我如何编码所选文件的复制和转换为byte[]数据有关。 The app is java based, and I have done this in Java before in a desktop app, so I just can't seem to find the issue.该应用程序是基于 Java 的,我之前在桌面应用程序中使用 Java 完成了此操作,所以我似乎无法找到问题所在。 Maybe it is a permission issue, I'm just not sure and someone standing outside looking in may see what I can't.也许这是一个许可问题,我只是不确定,站在外面的人可能会看到我看不到的东西。

What I have tried: Since the app can open various existing pre-populated files successfully from the DB, I've concentrated on and stepped through methods writing files to the DB.我尝试过的:由于该应用程序可以从数据库成功打开各种现有的预填充文件,因此我专注于并逐步介绍了将文件写入数据库的方法。 I'm not receiving any errors.我没有收到任何错误。 I suspect it may just be minor issue since I can't seem to see it.我怀疑这可能只是小问题,因为我似乎看不到它。

What I'm trying to do: I'm trying to emulate the desktop version of this app into a Android phone version.我正在尝试做的事情:我正在尝试将此应用程序的桌面版本模拟为 Android 手机版本。 I know it's not recommended or common practice to populate files to a DB, but this app needs to be able to read and write files to the DB supporting it.我知道不推荐或不常用的做法是将文件填充到数据库,但此应用程序需要能够读取和写入文件到支持它的数据库。 This will be a full range of file types like the desktop version (eg, pics, docs, audio, video, etc.).这将是各种文件类型,如桌面版本(例如,图片、文档、音频、视频等)。 However, as I stated above, .txt files seem to have no issue.但是,正如我上面所说,.txt 文件似乎没有问题。 The user can select files stored on their phone into a table that captures the fileName and filePath to a TableRow in a TableLayout .用户可以将存储在手机上的文件选择到一个表中,该表将fileNamefilePath捕获到TableLayoutTableRow Below are methods involved.下面是涉及的方法。 The plan is to refactor functionality once I get it working:计划是在我开始工作后重构功能:

Capturing the full path and filename for each row - Uses the captured filepath to convert to a byte[] to store the data.捕获每一行的完整路径和文件名- 使用捕获的文件路径转换为byte[]来存储数据。 The filename and file byte data are stored in a Files table, example, Files(fileName, fileData(byte[])).文件名和文件字节数据存储在 Files 表中,例如 Files(fileName, fileData(byte[]))。 Each file is added to an ArrayList<Files> which the method returns每个文件都添加到该方法返回的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;
}

Iteration of the ArrayList - The ArrayList<Files> is iterated and populated to the Files table and an ID capture to associate those files with a particular note of reference. 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));
        }
    }
}

Files Entity文件实体

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

First you are assuming that an insert works as per :-首先,您假设插入按以下方式工作:-

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

What if the row isn't inserted?如果没有插入行怎么办? and returns an id of -1?并返回-1的id?

So I'd suggest adding getters to the Files class such as :-所以我建议将 getter 添加到Files类,例如:-

public int getFileID() {
    return fileID;
}

public String getFileName() {
    return fileName;
}

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

and then add the following to FilesDao :-然后将以下内容添加到FilesDao 中:-

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

and then amending the addNewNoteFiles to be :-然后将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());
            }
        }
    }
}

Run and check the log.运行并查看日志。 Are all the files inserted?所有文件都插入了吗? Do the lengths match?长度匹配吗? Are the lengths as expected (if all 0 lengths, or some, then obviously something is amiss when building the ByteArrayOutputStream)长度是否符合预期(如果全部为 0 长度,或者一些长度,那么在构建 ByteArrayOutputStream 时显然有些问题)

You may wish to add similar for inserting the FilesByNote ie have the insert Dao return a long (it returns the rowid) and check if the value is > 0.您可能希望为插入 FilesByNote 添加类似的内容,即让插入 Dao 返回一个 long(它返回 rowid)并检查该值是否 > 0。

  • You may wonder what rowid is.您可能想知道 rowid 是什么。 Well it's a normally hidden column, perhaps hidden as it would appear that FilesByNotes is an associative table mapping(associating) Note(s) with Files and as such has a composite primary key NoteId and FileId which is not an alias of the rowid, so rowid will be hidden as such.嗯,它是一个通常隐藏的列,可能是隐藏的,因为 FilesByNotes 是一个关联表映射(关联)Note(s) 与文件,因此具有复合主键 NoteId 和 FileId,它不是 rowid 的别名,所以rowid 将被隐藏。 However, the value will be auto-generated or -1 if no row is inserted.但是,如果没有插入行,该值将自动生成或 -1。
    • ALL tables, with the exception of tables defined with WITHOUT ROWID, have a rowid column.除了使用 WITHOUT ROWID 定义的表外,所有表都有一个 rowid 列。 Room does not allow thee definition of WITHOUT ROWID tables. Room 不允许定义 WITHOUT ROWID 表。

You wouldn't be concerned about the value if it's greater than 0, just that it is greater than 0 and thus a row was inserted.如果它大于 0,您就不会关心该值,只要它大于 0 并因此插入了一行。

The above may help to determine any issues encountered when inserting the data.以上可能有助于确定插入数据时遇到的任何问题。 If there are none found then the issue is else where.如果没有找到,那么问题出在其他地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM