問題:我的 Android 手機應用程式可以打開存盤在Android Room預填充SQLite資料庫中的各種檔案型別,但無法打開應用程式本身添加到預填充資料庫中的檔案(除非它可以打開 .txt 檔案)。我相信問題可能與我如何編碼選定檔案到byte[]資料的復制和轉換有關。該應用程式是基于 Java 的,我之前在桌面應用程式中使用 Java 完成了此操作,所以我似乎無法找到問題所在。也許這是一個許可問題,我只是不確定,站在外面的人可能會看到我看不到的東西。
我嘗試過的:由于該應用程式可以從資料庫成功打開各種現有的預填充檔案,因此我專注于并逐步介紹了將檔案寫入資料庫的方法。我沒有收到任何錯誤。我懷疑這可能只是小問題,因為我似乎看不到它。
我正在嘗試做的事情:我正在嘗試將此應用程式的桌面版本模擬為 Android 手機版本。我知道不推薦或不常用的做法是將檔案填充到資料庫,但此應用程式需要能夠讀取和寫入檔案到支持它的資料庫。這將是各種檔案型別,如桌面版本(例如,圖片、檔案、音頻、視頻等)。但是,正如我上面所說的,.txt 檔案似乎沒有問題。用戶可以選擇手機中存盤的檔案到捕獲的一個表fileName,并filePath到TableRow一個TableLayout。下面是涉及的方法。計劃是在我開始作業后重構功能:
捕獲每一行的完整路徑和檔案名- 使用捕獲的檔案路徑轉換為 ??abyte[]以存盤資料。檔案名和檔案位元組資料存盤在 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;
}
}
uj5u.com熱心網友回復:
首先,您假設插入按以下方式作業:-
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 并因此插入了一行。
以上可能有助于確定插入資料時遇到的任何問題。如果沒有找到,那么問題出在其他地方。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/362122.html
標籤:爪哇 数组 文件 android-room
