File creation assets android - android

I'm buiding an app that what it does is scan the root folder
and then it searches if there is any folder inside... the purpose of this is to save all the
text files routes in database..the database will contain the textfile name and the route.
this is part of the code:
private void seedData(int indent, File file) throws IOException {
if (file.isDirectory()) {
File[] files = file.listFiles();
for (int i = 0; i < files.length; i++)
{
seedData(indent + 4, files[i]);
path+=files[i].getPath();
}
}
else{
db.execSQL("insert into "+TABLE+" (title, url) values ('"+
file.getName().substring(0, file.getName().length()-4)+"', '"+file.getPath()+"');");
}
}
but in normal Java I just create a File with the route and then send it to the method like
this: seedData(1, new File("/root")); .So my question is, how do I do this in Android? or to be more precise, how do I create a file that points to the root folder that is located in assets so it gets "scanned" by my code. I already tried seedData(1, new File("/assets/root")); but it just didnt work.
Any help would be much appreciated.
Note: No, I cannot save the paths manually since there is over 3k text files in all those subfolders.

The problem here is that the assets are not files. The Android equivalent of your above method would be something like this:
private void seedData(int indent, String path, AssetManager mgr)
throws IOException
{
String[] list = mgr.list(path);
if (list.length > 0) {
// path is a directory with something in it
for (String item : list) {
seedData(indent + 4, path + "/" + item, mgr);
}
} else {
// path is either an empty directory or a file
// unfortunately, Android makes it hard to distinguish
String name = path.substring(path.lastIndexOf('/') + 1);
db.execSQL("insert into "+TABLE+" (title, url) values ('"
+name.substring(0, name.length()-4)+"', '"
+path+"');");
}
}
You would call this from your Activity with
seedData(0, "root", getAssets());
For reference, the URI format for assets in the "root" folder is file:///android_asset/root/....

Related

Check If String Exists In Array Using Array.asList(myArray) Doesnt Work

I am trying to see if FTP files exists on server before uploading them as I am using FTP4J library which uploads existing files (overwrites) but my check does not work even though the file exists in the array:
for (String ftpFolder : my_ftpFolders)
{
FTPFile[] list = ftpClient.list(ftpFolder);
for (int i = 0; i < list.length; i++)
{
String ftpFile = list[i].getName();
Log.v("LOG", "zzz_ARRAY: " +Arrays.asList(myFiles));
Log.v("LOG", "zzz_ftpFile: " +ftpFile);
if (Arrays.asList(myFiles).contains(ftpFile))
{
Log.v("LOG", "zzz_ftpFile EXIST: " +ftpFile);
}else{
Log.v("LOG", "zzz_ftpFile NOT EXIST: " +ftpFile);
}
}
}
Array Print (Arrays.asList(myFiles)):
[[/storage/emulated/0/Download/mohamed-nohassi-odxB5oIG_iA-unsplash.jpg, /storage/emulated/0/Download/atheek-mohomed-e0JOwGDsUHQ-unsplash.jpg]]
ftpFile Print:
mohamed-nohassi-odxB5oIG_iA-unsplash.jpg
As you can see, the file exists in the array but Array.asList(myFiles) returns false
That is because you are trying to seach the string mohamed-nohassi-odxB5oIG_iA-unsplash.jpg
in a list that does not contains it. The value in the list is /storage/emulated/0/Download/mohamed-nohassi-odxB5oIG_iA-unsplash.jpg, that is clearly different.
To obtain the result you're trying to achieve, you have to split the file name, and get rid of the path. You can do it with some string manipulation. First, import Collectors:
import java.util.stream.Collectors;
Then, you can use this code to test if the list contains the file:
if (Arrays.asList(myFiles).stream().map(el -> {
String[] tokenized = el.split("/");
return tokenized.length > 0 ? tokenized[tokenized.length-1] : "";
}).collect(Collectors.toList()).contains(ftpFile))
With this code, for each element in the list you're getting just the last part after the last "/", then you're checking if the ftpFile is contained in the list you'll obtain after taking only all the last parts.

How do I rename a file from a "word" to a variable?

How do I rename a text file from "savedfile.txt" to variable ".txt"?
The user enters text, saved in a string called message. Presses the save button. Right now, a file called savedfile.txt is generated. If I input 1234, I want my file to be called 1234.txt.
public void sendClick(View view) {
// TODO : RENAME FILE TO INPUT VARIABLE
File file = new File (path + "/savedfile.txt");
String[] saveText = String.valueOf(messages.getText()).split(System.getProperty("line.separator") );
messages.setText("");
Save (file, saveText);
String message = messages.getText().toString();
writeLine("Saved ski #: " + message);
Instead of using "/savedfile.txt" you need a variable for the name.
File file = new File(path + "/" + message + ".txt")
Collect your input from the user. Check if it has a number, if it does then you store the filename as the numbers else you store the file name as message.txt. You need to add the smarts so that if user enters "hello123" you treat that accordingly.

How to get CSVWriter to add blob data into cell

I have an application that allows the user to sign the tablet and an image will be produced. That part I have working with confirmation as I am able to view the images after they are created and saved.
I am writing them to a .csv file with the following code.
//region - Create CSV file
writer = new CSVWriter(new FileWriter(sdCardPath + "Orders_Summary_Report.csv"), ',', CSVWriter.NO_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER, "\r\n");
//writer.writeNext(CSVcursor.getColumnNames()); //Write the column headings first before the looping starts
String [] headings = ("Order Id,Item ID,Item Name,Item Price,Item Count,Item Total,Paid Amount,VOID Order,Payment Method,Order Signature,Member/Authorization,Tab Number,Order Time").split(",");
writer.writeNext(headings);
for(CSVcursor.moveToFirst(); !CSVcursor.isAfterLast(); CSVcursor.moveToNext()) //Loop through all results (use row count of table)
{
String[] entries = (CSVcursor.getInt(CSVcursor.getColumnIndex("orderId"))+ ","
+CSVcursor.getInt(CSVcursor.getColumnIndex("itemId"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("itemName"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("itemPrice")) + ","
+CSVcursor.getInt(CSVcursor.getColumnIndex("itemCount"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("itemTotal"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("orderPaid"))+ ","
+CSVcursor.getInt(CSVcursor.getColumnIndex("orderVoid"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("orderType"))+ ","
+CSVcursor.getBlob(CSVcursor.getColumnIndex("orderSignature"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("referenceId"))+ ","
+CSVcursor.getInt(CSVcursor.getColumnIndex("orderTab"))+ ","
+CSVcursor.getString(CSVcursor.getColumnIndex("orderTime"))).split(","); //Split the string by the delimiter
writer.writeNext(entries); //Write current row of DB to file
writer.flush(); //Flush the stream
}
writer.close();
The file is getting written to successfully, but when I view the .csv file, the column that is saving the blob data looks like this.
B#2342342
B#2123982
B#3952929
It looks like I'm just saving the signature or some other attribute of the file rather than the file itself.
Do I need to stream the blob by bit/buffer into the csv file?
Just echoing #CommonsWare. The right thing to do is save the blob to the disk as am image. That way it can be easily retrieved for embedding into a file if needed. I still save my images to the db as blobs and just display them in a view. If you want to put these files into a csv, I would consider another type like pdf.

SQLiteDiskIOException: disk I/O error (code 3850)

I get above mentioned error on some devices (very rarely, 2 times until now only):
android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 3850)
at android.database.sqlite.SQLiteConnection.nativeExecuteForString(Native Method)
at android.database.sqlite.SQLiteConnection.executeForString(SQLiteConnection.java:679)
at android.database.sqlite.SQLiteConnection.setJournalMode(SQLiteConnection.java:361)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:236)
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:200)
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:463)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:185)
at android.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:177)
at android.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:806)
at android.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:791)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
at android.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
at ***.a(***.java:115)
The line 115 in my code is following:
// here the exception occurs
SQLiteDatabase db = SQLiteDatabase.openDatabase(pathApp, null, SQLiteDatabase.OPEN_READONLY);
// ...
db.close();
Story
What I do is following:
app has root rights
it copies the database from another app into it's own directory
it tries to open this database and read some data
it close the file again
That's all. This is working on thousands of devices. My app for sure only accesses the database at on place, I'm completely sure about that
Question
Does anyone know what could cause this problem?
Maybe interesting facts
the 2 devices are a OnePlus2
one guy told me that the problem occurred after updating to Oxygen 2.1
I came across a similar problem recently where my app runs fine on all Android devices except the OnePlus Two running OxygenOS 2.1.
After looking into the issue, it appears this specific combination is very sensitive and crashes on a database lock of some sort. In my case, my app was copying a new database to the device on the first run then checking the database version to see if it requires an update. On the check it crashed on these devices. I realized in my code I am opening a separate instance to the database instead of using the currently opened database when checking the version. After changing the code to avoid opening a separate instance of the database, the app stopped crashing on the OnePlus.
My advice is to Not open multiple instances of the database in your app or try closing the database first before opening it again (perhaps your copy method didn't close the database or is using another instance of the same database).
Just encountered this in development. It triggered when the phone ran out of batteries and shut down. Presumably, you just have to be grabbing the database lock when that happens.
Here's the working solution (already tested in production for 2 months now or so) and this works on the OnePlus2 and on Android 6 as well:
add the sqlite binaries to your app (can be found here: http://forum.xda-developers.com/showthread.php?t=2730422). Just put them into your apps assets folder
Then in your app, try to read an external database like following:
Find out which binary is working. I tried a few methods (via calling /proc/cpuinfofor example) but could not find a reliable solution, so I do it via trial and error like following:
First I copy the binary from my assets folder to my apps files folder
Then I try to dump the desired database via <path_to_SQLite3_bnary> <path_to_database> \.dump '<tablename>'\n and read the result
I check the result, if it contains error: I know the binary is not working, if it starts with INSERT INTO I know it works
I repeat this with my binaries until I found a working binary
Then I just read the result. The result will contain an error or be some csv similar content. I either handle the error or convert every line to valid csv via row.replace("INSERT INTO \"" + tablename + "\" VALUES(", "").replace(");", ""), so that I get the content in a csv format. I use opencsv's CSVReader to parse the data then...
That's it, this works (until know) on all devices without a problem
Code - copied from my sources, adopt it a little bit to fit your needs
public static List<String> readCSVData(String pathDatabase, String tableName) throws InterruptedException, TimeoutException, RootDeniedException, IOException
{
List<String> res = null;
List<String> csvData = null;
final String[] architectures = new String[]{
"armv7",
"armv7-pie",
"armv6",
"armv6-nofpu"
};
for (int i = 0; i < architectures.length; i++)
{
res = readDatabase(architectures[i], pathDatabase, tableName, rootMethod);
if (res.toString().contains("[error:"))
{
L.d(RootNetworkUtil.class, "Trial and Error - ERROR: " + architectures[i]);
}
else
{
int maxLength = (res.toString().length() < 100) ? res.toString().length() : 100;
L.d(RootNetworkUtil.class, "Trial and Error - RESULT: " + res.toString().substring(0, maxLength));
L.d(RootNetworkUtil.class, "Architecture found via trial and error: " + architectures[i]);
csvData = res;
break;
}
}
return csvData;
}
private static List<String> readDatabase(String architecture, String pathDB, String tablename) throws InterruptedException, TimeoutException, RootDeniedException, IOException {
String sqlite = "sqlite3." + architecture;
String pathSQLite3 = getSQLitePath(architecture, tablename);
// OWN class, just copy the file from the assets to the sqlite3 path!!!
AssetUtil.copyAsset(sqlite, pathSQLite3);
String[] cmd = new String[]{
"su\n",
//"chown root.root " + pathSQLite3 + "\n",
"chmod 777 " + pathSQLite3 + "\n",
pathSQLite3 + " " + pathDB + " \".dump '" + tablename + "'\"\n"
};
List<String> res = new ArrayList<>();
List<String> temp = RootUtils.execute(cmd);
for (int i = 0; i < temp.size(); i++)
{
// Fehlerzeilen behalten!!!
if (temp.get(i).contains("error:"))
res.add(temp.get(i));
else if (temp.get(i).startsWith("INSERT INTO \"" + tablename + "\""))
res.add(temp.get(i).replace("INSERT INTO \"" + tablename + "\" VALUES(", "").replace(");", ""));
}
return res;
}
public static String getSQLitePath(String architecture, String addon)
{
String sqlite = "sqlite3." + architecture;
String pathSQLite3 = "/data/data/" + MainApp.get().getPackageName() + "/files/" + sqlite + addon;
return pathSQLite3;
}

Appcelerator / Android: Unable to list second level directories with filesystem

I need help with an application i am working with in Appcelerator Titanium for Android.
I got the following code which allows me to show the first (root) level of the attached SD to the emulator (image sample follows):
/*
*
* Dynamic data,
* taken from the SD card
*
*/
//Get the SD card reference
var dir = Titanium.Filesystem.getFile(Titanium.Filesystem.externalStorageDirectory);
//Get the directory listing
var directoryStr = dir.getParent().getDirectoryListing();
//Convert the listing into an array for display in tableview
var directoryArr = directoryStr.toString().split(',');
//Initialize tabledata
var dirData = [];
for (var i=0; i < directoryArr.length; i++) {
dirData.push({ leftImage:'/images/folder.png', title: directoryArr[i], value: Titanium.Filesystem.externalStorageDirectory + Titanium.Filesystem.separator + directoryArr[i], hasChild:true });
Ti.API.info(Titanium.Filesystem.externalStorageDirectory + directoryArr[i]);
};
//Table view for directories
var tableDirs = Ti.UI.createTableView({
data: dirData
});
That outputs this:
The following code should give me the string that lists the directories inside, for example, Images directory in the above image.
tableDirs.addEventListener('click', function (e) {
if (e.rowData.hasChild) {
//Get the SD card reference
var secDir = Titanium.Filesystem.getFile(Titanium.Filesystem.externalStorageDirectory + '/' + e.rowData.title);
//Get the directory listing
var secDirStr = secDir.getDirectoryListing();
alert(secDirStr);
};
});
But instead, i get this:
Returns me an object that i don't know how to handle.
Sometimes if i use the following code:
var dir = Titanium.Filesystem.getFile(Titanium.Filesystem.externalStorageDirectory + '/Images');
The directory listing returns me a file 'deploy.json'.
Any pointers will be greatly appreciated. I'm fairly new to Android development, so i might be missing something obvious.
Thanks in advance!.
getDirectoryListing() returns an array. To view its contents, you'd have to look at the specific item in the array like: secDirStr[0].toString();
Try the for-loop below to view its contents:
if (e.rowData.hasChild) {
//Get the SD card reference
var secDir = Titanium.Filesystem.getFile(Titanium.Filesystem.externalStorageDirectory + '/' + e.rowData.title);
//Get the directory listing
var secDirStr = secDir.getDirectoryListing();
for (i=0, max=secDirStr.length; i<max; i++){
alert(secDirStr[i].toString());
}
};

Categories

Resources