0

问题:我的 Android 手机应用程序可以打开存储在Android Room预填充SQLite数据库中的各种文件类型,但无法打开应用程序本身添加到预填充数据库中的文件(除了可以打开 .txt 文件)。我认为问题可能在于我如何将所选文件的复制和转换编码为byte[]数据。该应用程序是基于 Java 的,我之前在桌面应用程序中使用 Java 完成了此操作,所以我似乎无法找到问题所在。也许这是一个许可问题,我只是不确定,站在外面看的人可能会看到我看不到的东西。

我尝试过的:由于该应用程序可以从数据库中成功打开各种现有的预填充文件,因此我专注于并逐步完成将文件写入数据库的方法。我没有收到任何错误。我怀疑这可能只是小问题,因为我似乎看不到它。

我正在尝试做的事情:我正在尝试将此应用程序的桌面版本模拟为 Android 手机版本。我知道不建议或不习惯将文件填充到数据库中,但这个应用程序需要能够读取和写入支持它的数据库中的文件。这将是各种文件类型,如桌面版本(例如,图片、文档、音频、视频等)。但是,如上所述,.txt 文件似乎没有问题。用户可以将存储在手机上的文件选择到一个表格中,该表格fileName捕获. 以下是涉及的方法。计划是在我开始工作后重构功能:filePathTableRowTableLayout

捕获每一行的完整路径和文件名- 使用捕获的文件路径转换为 ​​abyte[]来存储数据。文件名和文件字节数据存储在文件表中,例如 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;
    }
}
4

1 回答 1

1

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

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

如果没有插入行怎么办?并返回 -1 的 id?

所以我建议在Files类中添加 getter,例如:-

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);

and then amending the addNewNoteFiles to be :-

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)

You may wish to add similar for inserting the FilesByNote i.e. have the insert Dao return a long (it returns the rowid) and check if the value is > 0.

  • You may wonder what rowid is. 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. However, the value will be auto-generated or -1 if no row is inserted.
    • ALL tables, with the exception of tables defined with WITHOUT ROWID, have a rowid column. Room does not allow thee definition of WITHOUT ROWID tables.

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.

The above may help to determine any issues encountered when inserting the data. If there are none found then the issue is else where.

于 2021-11-12T21:02:47.410 回答