Speichern mit getFilesDir() geht im Emulator, auf Device aber nicht mehr - Warum?

  • Antworten:8
  • OffenNicht stickyNicht beantwortet
  • Forum-Beiträge: 690

06.05.2016, 20:27:07 via Website

Hallo,

meine App speichert Daten in 2 Dateien. Genauer: Über eine Netzwerkverbindung werden Daten empfangen und als Datei (CubeRawData.dat) gespeichert. Den Ort für das Speichern ermittele ich über getFilesDir(). Aus dieser Datei wird dann später wieder gelesen und die Daten in anderer Form gespeichert.
Wenn ich diesen Ablauf im Emulator durchführe, wird die erste Datei auch gespeichert, so dass sie später am gleichen Ort auch wieder gefunden und gelesen werden kann.
Wenn ich diesen Ablauf allerdings auf meinem Smartphone (ein GalaxyS5 mit Android 6) laufen lasse, wird die Datei nicht gefunden. LogCat zeigt mir dann diese Zeile an:

java.io.FileNotFoundException: /data/user/0/com.gumproductions.CubeControl/files/CubeRawData.dat: open failed: ENOENT (No such file or directory)

Ich hatte eigentlich gedacht, dass ich mit getFilesDir()ein beschreibbares Verzeichnis erhalte - die Daten sind ausschließlich für die App selbst wichtig.
Die Verwendung einer SD-Card wäre sicher möglich, allerdings möchte ich ungern eine SD-Card vorausetzen. Auch eine sqlite-Datenbank fällt aus, allerdings mehr wegen des dafür nötigen Overheads.
In meiner AndroidManifest.xml sind bereits

<uses-permission android:name="android.permission.CAMERA"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>

gesetzt.
Jetzt stellt sich die Frage: Liegt es an fehlenden Permissions? Wenn ja, welche? Liegt es daran, dass ich ein beschreibbares Verzeichnis mit einer anderen Methode erhalten muss? Welche?
Im Moment hängt die gesamte Weiterentwicklung an diesem Problem - es wäre ärgerlich, wenn ichjetzt alles abbrechen müsste, weil da was nicht (mehr) funktioniert.
Danke und Gruss
G.-U.M.

N'y pas n'y
tu car tu
mal tu mal

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.174

07.05.2016, 10:18:29 via App

Unter Android6 sind die Rechte wirklich anders.
Aber eigentlich nur auf den Internen Speicher und für "AppDir" brauchst du garkeine Permission.

Aber wenn FileNot Found dann wird er ja nicht erstellt. Also liegt es nicht am laden sondern am speichern.
Zeig mal deinen Code zum speichern.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 690

07.05.2016, 10:34:46 via Website

Pascal P.

Unter Android6 sind die Rechte wirklich anders.
Aber eigentlich nur auf den Internen Speicher und für "AppDir" brauchst du garkeine Permission.

Dazu hatte ich ja auch überhaupt keine Permission gefunden. Das mit der Kamera war mehr so ein Versuch, nicht das der Zugriff evtl. über diese Permission geregelt wird.

Aber wenn FileNot Found dann wird er ja nicht erstellt. Also liegt es nicht am laden sondern am speichern.
Zeig mal deinen Code zum speichern.

Gern (ich vermute mal, inzwischen kennst du meinen Stil :D: ):

 public class ast_MaxCube_DatenAbruf extends AsyncTask<String, Void, Void> {

        private InetAddress CubeIPAddress;
        private int CubeIPPort;

        @Override
        protected Void doInBackground(String... params) {
            try {
                Log.d("TCP", "Verbindung herstellen");
                CubeIPPort = 62910;
                Socket CubeSocket = new Socket(params[0], 62910);
                Log.d("TCP","Connection");
                act_MainCubeControl.CubeSocketStream = CubeSocket.getInputStream();
                Log.d("Storage","Daten vorhanden. Speicherpfad ermitteln");

                File CubeRawDatei = new File(getFilesDir(), "CubeRawData.dat");
                OutputStream out = new FileOutputStream(CubeRawDatei);
                byte[] buf = new byte[1024];
                int len;
                while ((len=CubeSocketStream.read(buf)) >0) {
                    out.write(buf,0,len);
                }
                out.close();

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return null;
        }

     }

Danke und Gruss
G.-U.M.

N'y pas n'y
tu car tu
mal tu mal

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.174

07.05.2016, 13:46:38 via App

Und eine Exceltion wird im AsyncTask nicht ausgelöst?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 690

07.05.2016, 17:13:46 via Website

Pascal P.

Und eine Exceltion wird im AsyncTask nicht ausgelöst?

Keine Ahnung. Wenn ich im Einzelschritt-Modus durchgehe, komme ich ans Speichern gar nicht heran - der Debugger springt leider nicht in die separate Task. Warum auch immer.
Aber dadurch hast du mich auf eine Idee gebracht bzw. dafür gesorgt, dass ich der Lösung wahrscheinlich näher komme: Ich prüfe beim Start der App nur nach, ob die zweite Datei vorhanden ist. Wenn die erste Datei vorhanden ist, wird diese verwendet. Und ich hab diese Datei in einer der ersten Entwicklungsstufen erzeugt und dann nie wieder gelöscht. Allerdings hab ich später die Aufrufe für die Abruf- und Speicher-Task geändert. Der Aufruf sieht jetzt komplett so aus:

try {
                xmlDatei.createNewFile();
                Log.d("Init","Cube-Daten abrufen...");
                new ast_MaxCube_DatenAbruf().execute("192.168.0.4");
                Log.d("Init", "Cube-Daten abgerufen und geschrieben");
                File CubeRawDaten = new File(getFilesDir(),"CubeRawData.dat");  // diese Datei wird im separaten Thread angelegt und geschrieben (muss hier
                // nur nochmal vorbereitet werden
                //cCN.cmm_CubeDatenSpeichern3Xml(xmlDatei, CubeRawDaten);
              //  cCN.cmm_DatenSpeichernJson(xmlDatei,CubeRawDaten);
                cCN.saveDevicesAsJason(xmlDatei,CubeRawDaten);
            } catch (IOException e) {
                e.printStackTrace();
            }

Und ich vermute, dass ich durch die Zeile

File CubeRawDatei = new File(getFilesDir(), "CubeRawData.dat");

mir den Zugriff versperre. Die Datei wird mit dem Namen CubeRawData.dat innerhalb der Task geschrieben. Wie kann ich denn später über ein File-Objekt wieder an diese Datei gelangen, um den Aufruf von cCN.saveDevicesAsJason(xmlDatei,CubeRawDaten)zu behalten? (Deklaration lautet:

public void saveDevicesAsJason(File VerwaltungXmlDatei, File CubeDataFile)

Vielen Dank für's "Durchwühlen-und-Verstehen".
Gruss

G.-U.M.

N'y pas n'y
tu car tu
mal tu mal

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.174

07.05.2016, 18:07:04 via App

Ich bin mir nicht ganz sicher was new File(...,...) macht. Baue dir den Pfad aus 2 Strings zusammen und dann new File(path);
Oder du liest den File direkt mit einem StreamReader obwohl ja das auch mit FileObjekt gehen müsste.

Ja debuggen in Threads ist manchmal komisch Aber um Festzustellen ob da was nicht past schaust du einfach ins Log. Da müsstest du bei Fehler die Exception sehen.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 690

07.05.2016, 19:27:30 via Website

Pascal P.

Ich bin mir nicht ganz sicher was new File(...,...) macht. Baue dir den Pfad aus 2 Strings zusammen und dann new File(path);
Oder du liest den File direkt mit einem StreamReader obwohl ja das auch mit FileObjekt gehen müsste.

Ich habs ganz anders gemacht. Siehe weiter unten.

Ja debuggen in Threads ist manchmal komisch Aber um Festzustellen ob da was nicht past schaust du einfach ins Log. Da müsstest du bei Fehler die Exception sehen.

Die hab ich jetzt sogar gefunden - allerdings sagt sie mir auch nur, dass die Datei nicht geschrieben werden kann.

Der Auszug aus Logcat:

76-104/system_process I/WindowManager﹕ createSurface Window{414aef60 Starting com.gumproductions.CubeControl paused=false}: DRAW NOW PENDING
05-07 17:15:06.766       76-231/system_process I/ActivityManager﹕ Start proc com.gumproductions.CubeControl for activity com.gumproductions.CubeControl/.act_MainCubeControl: pid=4776 uid=10044 gids={3003, 1006, 1015}
05-07 17:15:06.946       76-114/system_process W/NetworkManagementSocketTagger﹕ setKernelCountSet(10044, 1) failed with errno -2
05-07 17:15:07.796    4776-4776/com.gumproductions.CubeControl D/Callback﹕ In Callback: onCreate
05-07 17:15:07.806    4776-4776/com.gumproductions.CubeControl D/Init﹕ Cube-Daten abrufen...
05-07 17:15:07.826    4776-4776/com.gumproductions.CubeControl D/Init﹕ Cube-Daten abgerufen und geschrieben
05-07 17:15:07.826    4776-4776/com.gumproductions.CubeControl W/System.err﹕ java.io.FileNotFoundException: /CubeRawDaten: open failed: ENOENT (No such file or directory)
05-07 17:15:07.836    4776-4776/com.gumproductions.CubeControl W/System.err﹕ at libcore.io.IoBridge.open(IoBridge.java:406)

Und hier ausschnittweise der Aufruf für's Abrufen der Daten sowie dann das Speichern (ich hab die Log.d.- Aufrufe extra gelassen, um sie mit dem LogCat zu vergleichen):

try {
                xmlDatei.createNewFile();
                Log.d("Init","Cube-Daten abrufen...");
                new ast_MaxCube_DatenAbruf().execute("192.168.0.4");
                Log.d("Init", "Cube-Daten abgerufen und geschrieben");

                cCN.saveDevicesAsJson(xmlDatei,"CubeRawDaten");
            } catch (IOException e) {
                e.printStackTrace();
            }

            Log.d("Init", "Cube-Daten gesetzt");


 protected Void doInBackground(String... params) {
            try {
                Log.d("TCP", "Verbindung herstellen");
                CubeIPPort = 62910;
                Socket CubeSocket = new Socket(params[0], 62910);
                Log.d("TCP","Connection");
                act_MainCubeControl.CubeSocketStream = CubeSocket.getInputStream();
                Log.d("Storage","Daten vorhanden. Speicherpfad ermitteln");
                File CubeRawDatei = new File(getFilesDir(), "CubeRawData.dat");
                OutputStream out = new FileOutputStream(CubeRawDatei);
                byte[] buf = new byte[1024];
                int len;
                while ((len=CubeSocketStream.read(buf)) >0) {
                    out.write(buf,0,len);
                }
                out.close();

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (UnknownHostException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return null;
        }

N'y pas n'y
tu car tu
mal tu mal

Antworten
Pascal P.
  • Mod
  • Blogger
  • Forum-Beiträge: 10.174

07.05.2016, 22:18:37 via App

Du musst den File erst anlegen.

z.b.
mit sowas wie
if(!file.exists())
file.mkdir();

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
  • Forum-Beiträge: 690

08.05.2016, 10:15:28 via Website

Pascal P.

Du musst den File erst anlegen.

Es geht eleganter.

z.b.
mit sowas wie
if(!file.exists())
file.mkdir();

Da sich beide Dateien, die ich brauche, zwingend im gleichen Verzeichnis befinden müssen und ich die eine (die XML-Datei) sowieso anlege:

            xmlDatei.createNewFile();
            // Daten abrufen....
            cCN.saveDevicesAsJson(xmlDatei,"CubeRawData.dat");    // <<--- geänderte Deklaration

Während des Daten abrufens wird die Datei angelegt ,und jetzt auch sauber geschrieben:

File CubeRawDatei = new File(getFilesDir(), "CubeRawData.dat");
                OutputStream out = new FileOutputStream(CubeRawDatei);
                byte[] buf = new byte[1024];
                int len;
                while ((len=CubeSocketStream.read(buf)) >0) {
                    out.write(buf,0,len);
                }
                out.flush();
                out.close();

Das Speichern ist jetzt so deklariert:

 public void saveDevicesAsJson(File VerwaltungXmlDatei, String CubeDataFileName)

und an den Dateinamen der Datendatei (das vorherige Problem mit dem new File= getFiles() )
komme ich jetzt so:

String cdrfFileName = VerwaltungXmlDatei.getParent()+File.separator+CubeDataFileName;

Die Dateien sind jetzt beide vorhanden - das funktioniert. Das Problem liegt jetzt woanders: nämlich beim Anzeige der ermittelten Daten (in meinem Fall die Räume). Das muss ich nochmal genauer angucken. Und dann mach ich, glaub ich, aber dafür ne neue Anfrage auf.

Danke und Gruss
G.-U.M.

N'y pas n'y
tu car tu
mal tu mal

Antworten

Empfohlene Artikel