External storage files not visible to laptop over USB - xamarin.forms

In an Android app (API 29) I'm writing a file that needs to be readable from a laptop over USB. It is written to emulated external storage. As expected, in an Android file manager on the physical device, I see the file at:
Internal Storage > Android > data > com.xxx.myapp > files > Directory Documents >
Exports > Databases > my file.dbf
However, from a USB-connected laptop I do not see the file using Android File Transfer (or even Android Studio's Device File Explorer). I do see private files at:
Internal Storage > Android > data > data > com.xxx.myapp > files > ...
Storage permission is enabled in app settings and USB debugging is enabled in developer settings.
Although it's apparently not supposed to be necessary, I've enabled the manifest settings ReadExternalStorage and WriteExternalStorage as well.
What must I do to make the file visible to the laptop?
My code is below (within a Xamarin Android dependency service).
public async Task WriteExternalFileFromStreamAsync ( string foldername, string subfoldername, string filename, Stream stream )
// Writes external file from given stream
{
await Task.Run ( () =>
{
try
{
// Create folder
Context currentContext = Android.App.Application.Context;
Java.IO.File directory = new Java.IO.File ( currentContext.GetExternalFilesDir( "directorydocuments" ).AbsolutePath + "/" + foldername );
directory.Mkdir ();
// Create subfolder
Java.IO.File subdirectory = new Java.IO.File ( currentContext.GetExternalFilesDir( "directorydocuments" ).AbsolutePath + "/" + foldername + "/" + subfoldername );
subdirectory.Mkdir ();
// Write file
string path = Path.Combine ( subdirectory.AbsolutePath, filename );
using ( FileStream filestream = new FileStream ( path, FileMode.Create, FileAccess.ReadWrite ) )
stream.CopyTo ( filestream );
}
catch ( Exception ex )
{
MyUtil.WriteLogFile ( S.Exception, ex.AsStringVal () );
throw;
}
});
}

It's working now, after various restarts / reboot. Sorry.

Related

Are websocket, playing audio in background, and storing files locally possible in KaiOS app?

I am planning to develop a chat and voice messaging app in KaiOS, but want to make sure whether these things are possible in KaiOS:
web sockets in background (can receive the data when app is not opened)
playing audio in background without user interaction
storing files locally
Web Sockets : Web sockets can work only if the app is at foreground. You can use window.MozWebSocket or websock.js.
If you want to do any data exchange activity in background, then make use of push notification, serviceworker and indexed db/cache API.
Storing files : Yes you can read and write files
To read,
var sdcard = navigator.getDeviceStorage('sdcard');
var request = sdcard.get("fileName");
request.onsuccess = function () {
var fileObject = this.result;
};
request.onerror = function () {
console.warn("Unable to get the file: " + this.error);
};
To write,
var sdcard = navigator.getDeviceStorage("sdcard");
var request = sdcard.addNamed("file data", "test.txt");
request.onsuccess = function () {
var name = this.result;
console.log('File "' + name + '" successfully wrote !!');
};
request.onerror = function () {
console.warn('Unable to write the file: ' + this.error);
}
Background WebSockets aren't supposed by any browser, or on KaiOS. You can use Web Push to receive push notifications in the background.
Background audio playback is supported
Files can be read and saved locally using the Device Storage API

Can't get the names of the files that exist in a specific directory using File or InputStream [duplicate]

I have a resources folder/package in the root of my project, I "don't" want to load a certain File. If I wanted to load a certain File, I would use class.getResourceAsStream and I would be fine!! What I actually want to do is to load a "Folder" within the resources folder, loop on the Files inside that Folder and get a Stream to each file and read in the content... Assume that the File names are not determined before runtime... What should I do? Is there a way to get a list of the files inside a Folder in your jar File?
Notice that the Jar file with the resources is the same jar file from which the code is being run...
Finally, I found the solution:
final String path = "sample/folder";
final File jarFile = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getPath());
if(jarFile.isFile()) { // Run with JAR file
final JarFile jar = new JarFile(jarFile);
final Enumeration<JarEntry> entries = jar.entries(); //gives ALL entries in jar
while(entries.hasMoreElements()) {
final String name = entries.nextElement().getName();
if (name.startsWith(path + "/")) { //filter according to the path
System.out.println(name);
}
}
jar.close();
} else { // Run with IDE
final URL url = Launcher.class.getResource("/" + path);
if (url != null) {
try {
final File apps = new File(url.toURI());
for (File app : apps.listFiles()) {
System.out.println(app);
}
} catch (URISyntaxException ex) {
// never happens
}
}
}
The second block just work when you run the application on IDE (not with jar file), You can remove it if you don't like that.
Try the following.
Make the resource path "<PathRelativeToThisClassFile>/<ResourceDirectory>" E.g. if your class path is com.abc.package.MyClass and your resoure files are within src/com/abc/package/resources/:
URL url = MyClass.class.getResource("resources/");
if (url == null) {
// error - missing folder
} else {
File dir = new File(url.toURI());
for (File nextFile : dir.listFiles()) {
// Do something with nextFile
}
}
You can also use
URL url = MyClass.class.getResource("/com/abc/package/resources/");
The following code returns the wanted "folder" as Path regardless of if it is inside a jar or not.
private Path getFolderPath() throws URISyntaxException, IOException {
URI uri = getClass().getClassLoader().getResource("folder").toURI();
if ("jar".equals(uri.getScheme())) {
FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap(), null);
return fileSystem.getPath("path/to/folder/inside/jar");
} else {
return Paths.get(uri);
}
}
Requires java 7+.
I know this is many years ago . But just for other people come across this topic.
What you could do is to use getResourceAsStream() method with the directory path, and the input Stream will have all the files name from that dir. After that you can concat the dir path with each file name and call getResourceAsStream for each file in a loop.
I had the same problem at hands while i was attempting to load some hadoop configurations from resources packed in the jar... on both the IDE and on jar (release version).
I found java.nio.file.DirectoryStream to work the best to iterate over directory contents over both local filesystem and jar.
String fooFolder = "/foo/folder";
....
ClassLoader classLoader = foofClass.class.getClassLoader();
try {
uri = classLoader.getResource(fooFolder).toURI();
} catch (URISyntaxException e) {
throw new FooException(e.getMessage());
} catch (NullPointerException e){
throw new FooException(e.getMessage());
}
if(uri == null){
throw new FooException("something is wrong directory or files missing");
}
/** i want to know if i am inside the jar or working on the IDE*/
if(uri.getScheme().contains("jar")){
/** jar case */
try{
URL jar = FooClass.class.getProtectionDomain().getCodeSource().getLocation();
//jar.toString() begins with file:
//i want to trim it out...
Path jarFile = Paths.get(jar.toString().substring("file:".length()));
FileSystem fs = FileSystems.newFileSystem(jarFile, null);
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(fs.getPath(fooFolder));
for(Path p: directoryStream){
InputStream is = FooClass.class.getResourceAsStream(p.toString()) ;
performFooOverInputStream(is);
/** your logic here **/
}
}catch(IOException e) {
throw new FooException(e.getMessage());
}
}
else{
/** IDE case */
Path path = Paths.get(uri);
try {
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path);
for(Path p : directoryStream){
InputStream is = new FileInputStream(p.toFile());
performFooOverInputStream(is);
}
} catch (IOException _e) {
throw new FooException(_e.getMessage());
}
}
Another solution, you can do it using ResourceLoader like this:
import org.springframework.core.io.Resource;
import org.apache.commons.io.FileUtils;
#Autowire
private ResourceLoader resourceLoader;
...
Resource resource = resourceLoader.getResource("classpath:/path/to/you/dir");
File file = resource.getFile();
Iterator<File> fi = FileUtils.iterateFiles(file, null, true);
while(fi.hasNext()) {
load(fi.next())
}
If you are using Spring you can use org.springframework.core.io.support.PathMatchingResourcePatternResolver and deal with Resource objects rather than files. This works when running inside and outside of a Jar file.
PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver();
Resource[] resources = r.getResources("/myfolder/*");
Then you can access the data using getInputStream and the filename from getFilename.
Note that it will still fail if you try to use the getFile while running from a Jar.
As the other answers point out, once the resources are inside a jar file, things get really ugly. In our case, this solution:
https://stackoverflow.com/a/13227570/516188
works very well in the tests (since when the tests are run the code is not packed in a jar file), but doesn't work when the app actually runs normally. So what I've done is... I hardcode the list of the files in the app, but I have a test which reads the actual list from disk (can do it since that works in tests) and fails if the actual list doesn't match with the list the app returns.
That way I have simple code in my app (no tricks), and I'm sure I didn't forget to add a new entry in the list thanks to the test.
Below code gets .yaml files from a custom resource directory.
ClassLoader classLoader = this.getClass().getClassLoader();
URI uri = classLoader.getResource(directoryPath).toURI();
if("jar".equalsIgnoreCase(uri.getScheme())){
Pattern pattern = Pattern.compile("^.+" +"/classes/" + directoryPath + "/.+.yaml$");
log.debug("pattern {} ", pattern.pattern());
ApplicationHome home = new ApplicationHome(SomeApplication.class);
JarFile file = new JarFile(home.getSource());
Enumeration<JarEntry> jarEntries = file.entries() ;
while(jarEntries.hasMoreElements()){
JarEntry entry = jarEntries.nextElement();
Matcher matcher = pattern.matcher(entry.getName());
if(matcher.find()){
InputStream in =
file.getInputStream(entry);
//work on the stream
}
}
}else{
//When Spring boot application executed through Non-Jar strategy like through IDE or as a War.
String path = uri.getPath();
File[] files = new File(path).listFiles();
for(File file: files){
if(file != null){
try {
InputStream is = new FileInputStream(file);
//work on stream
} catch (Exception e) {
log.error("Exception while parsing file yaml file {} : {} " , file.getAbsolutePath(), e.getMessage());
}
}else{
log.warn("File Object is null while parsing yaml file");
}
}
}
Took me 2-3 days to get this working, in order to have the same url that work for both Jar or in local, the url (or path) needs to be a relative path from the repository root.
..meaning, the location of your file or folder from your src folder.
could be "/main/resources/your-folder/" or "/client/notes/somefile.md"
Whatever it is, in order for your JAR file to find it, the url must be a relative path from the repository root.
it must be "src/main/resources/your-folder/" or "src/client/notes/somefile.md"
Now you get the drill, and luckily for Intellij Idea users, you can get the correct path with a right-click on the folder or file -> copy Path/Reference.. -> Path From Repository Root (this is it)
Last, paste it and do your thing.
Simple ... use OSGi. In OSGi you can iterate over your Bundle's entries with findEntries and findPaths.
Inside my jar file I had a folder called Upload, this folder had three other text files inside it and I needed to have an exactly the same folder and files outside of the jar file, I used the code below:
URL inputUrl = getClass().getResource("/upload/blabla1.txt");
File dest1 = new File("upload/blabla1.txt");
FileUtils.copyURLToFile(inputUrl, dest1);
URL inputUrl2 = getClass().getResource("/upload/blabla2.txt");
File dest2 = new File("upload/blabla2.txt");
FileUtils.copyURLToFile(inputUrl2, dest2);
URL inputUrl3 = getClass().getResource("/upload/blabla3.txt");
File dest3 = new File("upload/Bblabla3.txt");
FileUtils.copyURLToFile(inputUrl3, dest3);

sqlite jdbc error SQLITE_IOERR_LOCK

I have a runnable jar for a java8 program which uses sqlite-jdbc 3.14.2. It works fine on windows 10 and ubuntu. i.e. i can query stuff on these platforms on all the tables. However, when i run it on FreeBSD 10.3-releasep4, it gives me the following error when i run queries on all the tables.
[SQLITE_IOERR_LOCK] I/O error in the advisory file locking logic (disk I/O error) on FreeBSD 10.3-release
Please advise a workaround or solution.
Same issue exists with 3.16.1
So I finally found out what was wrong. It was an NFS mounted volume that was causing the problem. With DB file on local file system, it works like a charm.
If anyone is coming to this question at later time, this error can be reproduced by first creating or opening a DB with WAL journalling mode, writing something, then closing the DB and trying to open it again in read-only mode with journalling off. This unit test will reproduce the error:
#Test
public void mixJournalingModesFailureTest()
{
File tempDb = File.createTempFile("tempdbtest", ".db");
tempDb.deleteOnExit();
// Open a temp DB in RW mode with WAL journalling
String url = "jdbc:sqlite:" + tempDb.getAbsolutePath();
SQLiteConfig config = new SQLiteConfig();
// Ser read-write with WAL journalling
config.setJournalMode( SQLiteConfig.JournalMode.WAL );
config.setReadOnly( false );
Properties props = config.toProperties();
Connection conn = DriverManager.getConnection( url, props );
// Write something
try ( Statement statement = conn.createStatement() )
{
statement.execute( "CREATE TABLE test (words text)" );
}
// Close the DB
conn.close();
// Open the DB again but with journalling off and in read-only mode
config.setJournalMode( SQLiteConfig.JournalMode.OFF );
config.setReadOnly( true );
props = config.toProperties();
try
{
// This will throw the SQLITE_IOERR_LOCK advisory lock exception
DriverManager.getConnection( url, props );
fail( "Should throw advisory lock exception" );
}
catch ( SQLException ignore ) {}
}

Read CollectionFS file from server's filesystem when hosted on meteor.com

Im trying let the user Upload a txt file and then let him click a button "analyze" and then perform some analysis.
I have the app working locally, Im using FS.Collection and FileSystem however I had several problems deploying to meteor.com. Here is my collection:
FS.debug = true;
Uploads = new FS.Collection('uploads', {
stores: [new FS.Store.FileSystem('uploads')]
});
and here is how I try to read the uploaded file:
var fs = Npm.require('fs');
var readedFile = fs.readFileSync(process.env.PWD+'/.meteor/local/cfs/files/uploads/+file.copies.uploads.key, 'utf-8');
The above works in local but not after I deploy to meteor.com, in the debug messages I see something like this: Error: ENOENT, no such file or directory
So I do not know how to read the file when the app is deployed, how would you do it?, or do you think I should deploy the app to Amazon EC2? Im afraid to deploy to amazon and have the same problem...
Short example of using http to download a file that was uploaded via collectionFS.
var file = Uploads.findOne({ _id: myId }); // or however you find it
HTTP.get(file.url(),function(err,result){
// this will be async obviously
if ( err ) console.log("Error "+err+" downloading file"+myId);
else {
var content = result.content; // the contents of the file
// now do something with it
}
});
Note that you must meteor add http to get access to the http package.
This is probably the package you want:
https://github.com/tomitrescak/meteor-uploads
it has a nice UI too and much less trouble than FSCollection.

Channel.Security.Error...Error #2048

I recently upgraded to Flash Builder 4.5 for PHP and am trying to upload a release build to my remoteserver. When I try to make a php call from the app, I get the error:
Send failednChannel.Security.Error error Error #2048 url: 'http://localhost/my_php/public/gateway.php'
The release build works fine on my localhost machine. All of my php service calls are on my remote host. Here's the structure of my remote host:
/my_directory/html (this is the root directory)
/my_directory/html/my_php/public/release (this is where my .html wrapper and .swf files sit)
/my_directory/html/my_php/public (this is where my gateway.php and amf_config.ini files sit)
The error specifically references 'localhost', but I can't find where that gets set. When I google error #2048, the solutions point to a badly configured crossdomain file...all my services are on remotehost (where the app is hosted) so I don't think that could be the issue.
Here is my amf_config.ini file:
[zend]
webroot = "/my_directory/html"
zend_path ="/my_directory/html/ZendFramework/library"
library ="/my_directory/html/my_php/library"
services ="/my_directory/html/my_php/services"
[zendamf]
amf.production = false
amf.directories[]=/my_directory/html/my_php/services
Here is my gateway.php file:
<?php
ini_set("display_errors", 1);
$dir = dirname(__FILE__);
$webroot = $_SERVER['DOCUMENT_ROOT'];
$configfile = "$dir/amf_config.ini";
$servicesdir = $dir.'/../services';
$librarydir = $dir.'/../library';
//default zend install directory
$zenddir = $webroot.'/ZendFramework/library';
//Load ini file and locate zend directory
if (file_exists($configfile)) {
$arr = parse_ini_file($configfile, true);
if (isset($arr['zend']['webroot'])) {
$webroot = $arr['zend']['webroot'];
$zenddir = $webroot.'/ZendFramework/library';
}
if (isset($arr['zend']['zend_path'])) {
$zenddir = $arr['zend']['zend_path'];
}
if (isset($arr['zend']['library'])) {
$librarydir = $arr['zend']['library'];
}
if (isset($arr['zend']['services'])) {
$servicesdir = $arr['zend']['services'];
}
}
// Setup include path
// add zend directory, library and services to include path
set_include_path(get_include_path()
.PATH_SEPARATOR.$zenddir
.PATH_SEPARATOR.$librarydir
.PATH_SEPARATOR.$servicesdir);
// Initialize Zend Framework loader
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true)->suppressNotFoundWarnings(true);
// Load configuration
$default_config = new Zend_Config(array("production" => false), true);
$default_config->merge(new Zend_Config_Ini($configfile, 'zendamf'));
$default_config->setReadOnly();
$amf = $default_config->amf;
// Store configuration in the registry
Zend_Registry::set("amf-config", $amf);
// Initialize AMF Server
$server = new Zend_Amf_Server();
$server->setProduction($amf->production);
if (isset($amf->directories)) {
$dirs = $amf->directories->toArray();
foreach ($dirs as $dir) {
if ($dir == "./") {
$server->addDirectory($webroot);
} else
if (realpath("{$webroot}/{$dir}")) {
$server->addDirectory("{$webroot}/{$dir}");
} else
if (realpath($dir)) {
$server->addDirectory(realpath($dir));
}
}
}
// Initialize introspector for non-production
if (! $amf->production) {
$server->setClass('Zend_Amf_Adobe_Introspector', '',
array("config" => $default_config, "server" => $server));
$server->setClass('Zend_Amf_Adobe_DbInspector', '',
array("config" => $default_config, "server" => $server));
}
// Handle request
echo $server->handle();
i had the same problem in a flex - blaze - environment. The real Problem was the context-root in the project properties.
because you used flex 4.5, there is no input field for this setting. in flex builder 3, there was a setting in the project properties -> flex server -> context root.
i gone crazy and found after hours an article on adobes bugs-site [FB-22939].
That solve my problem. I have no idea, wich project settings you are using, try to search a string named {context.root} in your project or post a liite bit more about your project settings. i know blaze is different from php, but maybe it is a tip bringing you back on track.
Unfortunately I'm not able to reproduce my thread and setting up an php environment with more knowledge about your setup. (Server-Technology, and so one)
edit:
additional Info:
I've found a list of all compiler arguments. Try it with this argument:
-context-root <context-path>
full name -compiler.context-root
path to replace {context.root} tokens for service channel endpoints
br
Frank

Resources