Odczyt / zapis ciągu z / do pliku w systemie Android

213

Chcę zapisać plik w pamięci wewnętrznej, pobierając tekst z EditText. Następnie chcę, aby ten sam plik zwrócił wprowadzony tekst w postaci ciągu i zapisał go w innym ciągu, który będzie później używany.

Oto kod:

package com.omm.easybalancerecharge;


import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final EditText num = (EditText) findViewById(R.id.sNum);
        Button ch = (Button) findViewById(R.id.rButton);
        TelephonyManager operator = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        String opname = operator.getNetworkOperatorName();
        TextView status = (TextView) findViewById(R.id.setStatus);
        final EditText ID = (EditText) findViewById(R.id.IQID);
        Button save = (Button) findViewById(R.id.sButton);

        final String myID = ""; //When Reading The File Back, I Need To Store It In This String For Later Use

        save.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                //Get Text From EditText "ID" And Save It To Internal Memory
            }
        });
        if (opname.contentEquals("zain SA")) {
            status.setText("Your Network Is: " + opname);
        } else {
            status.setText("No Network");
        }
        ch.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub

                //Read From The Saved File Here And Append It To String "myID"


                String hash = Uri.encode("#");
                Intent intent = new Intent(Intent.ACTION_CALL);
                intent.setData(Uri.parse("tel:*141*" + /*Use The String With Data Retrieved Here*/ num.getText()
                        + hash));
                startActivity(intent);
            }
        });
    }

Zamieściłem komentarze, aby pomóc ci w dalszej analizie moich uwag na temat tego, gdzie chcę, aby operacje zostały wykonane / zmienne, które mają być użyte.

Major Aly
źródło
2
pytanie brzmi „jak czytać / zapisywać do / z pliku?”
Dmitri Gudkov
Czy rozważałeś użycie preferencji aplikacji do przechowywania swoich ciągów?
sdabet
4
BTW, upewnij się, że zezwoliłeś na plik Mainfest, do pracy z pamięcią ...
Dmitri Gudkov
To moja w połowie kompletna aplikacja z wieloma zmianami do wdrożenia. Moim pomysłem jest, aby użytkownik wprowadził identyfikator tylko raz przy pierwszym uruchomieniu aplikacji. Następnie aplikacja będzie odwoływać się do tego przechowywanego identyfikatora tyle razy, ile użytkownik uruchomi aplikację. Uprawnienia są dodawane do manifestu.
Major Aly

Odpowiedzi:

334

Mam nadzieję, że może ci się to przydać.

Napisz plik:

private void writeToFile(String data,Context context) {
    try {
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput("config.txt", Context.MODE_PRIVATE));
        outputStreamWriter.write(data);
        outputStreamWriter.close();
    }
    catch (IOException e) {
        Log.e("Exception", "File write failed: " + e.toString());
    } 
}

Czytaj plik:

private String readFromFile(Context context) {

    String ret = "";

    try {
        InputStream inputStream = context.openFileInput("config.txt");

        if ( inputStream != null ) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String receiveString = "";
            StringBuilder stringBuilder = new StringBuilder();

            while ( (receiveString = bufferedReader.readLine()) != null ) {
                stringBuilder.append("\n").append(receiveString);
            }

            inputStream.close();
            ret = stringBuilder.toString();
        }
    }
    catch (FileNotFoundException e) {
        Log.e("login activity", "File not found: " + e.toString());
    } catch (IOException e) {
        Log.e("login activity", "Can not read file: " + e.toString());
    }

    return ret;
}
R9J
źródło
43
Jeśli klasa nie jest rozszerzana z działania, użycie metody „openFileInput ()” powinno wyglądać następująco: context.openFileInput ()
Behzad
11
Uwaga: powyższy kod działa dobrze, ale wynikowy ciąg nie będzie zawierał żadnych podziałów wierszy z pliku. Aby ponownie dodać podziały wierszy, zmień wiersz „stringBuilder.append (receiveString);” na "stringBuilder.append (receiveString) .append (" \ n ");". Jeśli oczekujesz, że inne znaki podziału linii (np. Pliki tekstowe Windows będą miały \ r itp.), W swoim ostatnim ciągu będziesz musiał dostosować to nieco bardziej.
treesAreEverywhere
26
gdzie ten plik konfiguracyjny zapisuje się na prawdziwym urządzeniu? nie mogłem go znaleźć :(
Mahdi
4
Myślę, że zamykające strumienie powinny być w finalbloku, jak w odpowiedzi @SharkAlley
Yurii K
4
@ Kenji plik jest zapisywany w katalogu plików aplikacji (tj. / Data / data / <nazwa_pakietu> /files/config.txt). Proces aplikacji może uzyskać do niego dostęp, ale nie wszystkie procesy w systemie operacyjnym. Implementacja może się różnić w zależności od wersji Androida uruchomionej przez urządzenie. Możesz sprawdzić implementację AOSP online. Na przykład dla Androida 8.1_r5: android.googlesource.com/platform/frameworks/base/+/…
vhamon
187

Dla tych, którzy szukają ogólnej strategii odczytu i zapisu ciągu do pliku:

Najpierw pobierz obiekt pliku

Będziesz potrzebował ścieżki przechowywania. W przypadku pamięci wewnętrznej użyj:

File path = context.getFilesDir();

W przypadku pamięci zewnętrznej (karty SD) użyj:

File path = context.getExternalFilesDir(null);

Następnie utwórz obiekt pliku:

File file = new File(path, "my-file-name.txt");

Napisz ciąg do pliku

FileOutputStream stream = new FileOutputStream(file);
try {
    stream.write("text-to-write".getBytes());
} finally {
    stream.close();
}

Lub z Google Guava

Zawartość ciągu = Files.toString (plik, StandardCharsets.UTF_8);

Przeczytaj plik do łańcucha

int length = (int) file.length();

byte[] bytes = new byte[length];

FileInputStream in = new FileInputStream(file);
try {
    in.read(bytes);
} finally {
    in.close();
}

String contents = new String(bytes);   

Lub jeśli korzystasz z Google Guava

String contents = Files.toString(file,"UTF-8");

Dla kompletności wspomnę

String contents = new Scanner(file).useDelimiter("\\A").next();

który nie wymaga bibliotek, ale testy porównawcze są o 50% - 400% wolniejsze niż inne opcje (w różnych testach na moim Nexusie 5).

Notatki

Dla każdej z tych strategii zostaniesz poproszony o złapanie wyjątku IOException.

Domyślne kodowanie znaków w Androidzie to UTF-8.

Jeśli używasz pamięci zewnętrznej, musisz dodać do manifestu:

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

lub

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

Uprawnienie do zapisu oznacza uprawnienie do odczytu, więc nie potrzebujesz obu.

SharkAlley
źródło
Ok, na przykład chcę, aby użytkownik zobaczył wszystkie swoje posty, a kiedy przejdzie do innego ekranu i wróci, muszę go narysować ponownie lub ponieważ jest buforowany, po prostu wyciąga go z pamięci podręcznej i pokazuje, jeśli to po prostu go wyciąga, jak dodać warunkową
opcję,
4
Nie rób tego jak new File(path + "/my-file-name.txt");. To przeczy znacznemu sensowi File. Użyj new File(path, "my-file-name.txt");zamiast tego.
JimmyB,
@ HannoBinder Android zawsze działa na Linuksie, więc separatorem z pewnością jest „/”. Jaka byłaby korzyść z zastosowania nowego pliku (ścieżki, „my-file-name.txt”) w tym kontekście? (Cieszę się, że mogę zaktualizować odpowiedź, jeśli istnieje ku temu powód).
SharkAlley,
1
Filejest tam z jakiegoś powodu. W twoim przypadku równie dobrze możesz pominąć Filei po prostu zrobić new FileInputStream(path + "/my-file-name.txt");, czego nie polecam. (Co jeśli na przykład pathzawiera znak /
końca
Edytowane według Twojej sugestii. Dzięki :)
SharkAlley
37
public static void writeStringAsFile(final String fileContents, String fileName) {
    Context context = App.instance.getApplicationContext();
    try {
        FileWriter out = new FileWriter(new File(context.getFilesDir(), fileName));
        out.write(fileContents);
        out.close();
    } catch (IOException e) {
        Logger.logError(TAG, e);
    }
}

public static String readFileAsString(String fileName) {
    Context context = App.instance.getApplicationContext();
    StringBuilder stringBuilder = new StringBuilder();
    String line;
    BufferedReader in = null;

    try {
        in = new BufferedReader(new FileReader(new File(context.getFilesDir(), fileName)));
        while ((line = in.readLine()) != null) stringBuilder.append(line);

    } catch (FileNotFoundException e) {
        Logger.logError(TAG, e);
    } catch (IOException e) {
        Logger.logError(TAG, e);
    } 

    return stringBuilder.toString();
}
Eugene
źródło
7
Aplikacja! co to ma być!
Alap
@alap Jest czymś, czego @Eugene używa do statycznego pobierania kontekstu aplikacji. On tego potrzebuje context.getFilesDir(). Można po prostu zastąpić wystąpienia new File(context.getFilesDir(), fileName)z Fileobiektu lub Stringprzekazywane do funkcji zamiast fileName.
lorenzo-s
7

Tylko niewielkie modyfikacje odczytu ciągu z metody pliku dla większej wydajności

private String readFromFile(Context context, String fileName) {
    if (context == null) {
        return null;
    }

    String ret = "";

    try {
        InputStream inputStream = context.openFileInput(fileName);

        if ( inputStream != null ) {
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream);               

            int size = inputStream.available();
            char[] buffer = new char[size];

            inputStreamReader.read(buffer);

            inputStream.close();
            ret = new String(buffer);
        }
    }catch (Exception e) {
        e.printStackTrace();
    }

    return ret;
}
Tai Le Anh
źródło
6

sprawdź poniższy kod.

Odczytywanie z pliku w systemie plików.

FileInputStream fis = null;
    try {

        fis = context.openFileInput(fileName);
        InputStreamReader isr = new InputStreamReader(fis);
        // READ STRING OF UNKNOWN LENGTH
        StringBuilder sb = new StringBuilder();
        char[] inputBuffer = new char[2048];
        int l;
        // FILL BUFFER WITH DATA
        while ((l = isr.read(inputBuffer)) != -1) {
            sb.append(inputBuffer, 0, l);
        }
        // CONVERT BYTES TO STRING
        String readString = sb.toString();
        fis.close();

    catch (Exception e) {

    } finally {
        if (fis != null) {
            fis = null;
        }
    }

poniższy kod służy do zapisania pliku w wewnętrznym systemie plików.

FileOutputStream fos = null;
    try {

        fos = context.openFileOutput(fileName, Context.MODE_PRIVATE);
        fos.write(stringdatatobestoredinfile.getBytes());
        fos.flush();
        fos.close();

    } catch (Exception e) {

    } finally {
        if (fos != null) {
            fos = null;
        }
    }

Myślę, że to ci pomoże.

Raj
źródło
3

Jestem trochę początkującym i miałam problem z tym, żeby dzisiaj to zadziałało.

Poniżej jest klasa, z którą skończyłem. Działa, ale zastanawiałem się, jak niedoskonałe jest moje rozwiązanie. W każdym razie miałem nadzieję, że niektórzy z was, bardziej doświadczeni ludzie, będą skłonni spojrzeć na moją klasę IO i udzielić wskazówek. Twoje zdrowie!

public class HighScore {
    File data = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator);
    File file = new File(data, "highscore.txt");
    private int highScore = 0;

    public int readHighScore() {
        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            try {
                highScore = Integer.parseInt(br.readLine());
                br.close();
            } catch (NumberFormatException | IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            try {
                file.createNewFile();
            } catch (IOException ioe) {
                ioe.printStackTrace();
            }
            e.printStackTrace();
        }
        return highScore;
    }

    public void writeHighScore(int highestScore) {
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(file));
            bw.write(String.valueOf(highestScore));
            bw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Nihilarian
źródło
Nie musisz tworzyć nowego pliku, jeśli nie ma tam pliku.
rml
1

pierwszą rzeczą, której potrzebujemy, są uprawnienia w AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />

więc w klasie asyncTask Kotlin traktujemy tworzenie pliku

    import android.os.AsyncTask
    import android.os.Environment
    import android.util.Log
    import java.io.*
    class WriteFile: AsyncTask<String, Int, String>() {
        private val mFolder = "/MainFolder"
        lateinit var folder: File
        internal var writeThis = "string to cacheApp.txt"
        internal var cacheApptxt = "cacheApp.txt"
        override fun doInBackground(vararg writethis: String): String? {
            val received = writethis[0]
            if(received.isNotEmpty()){
                writeThis = received
            }
            folder = File(Environment.getExternalStorageDirectory(),"$mFolder/")
            if(!folder.exists()){
                folder.mkdir()
                val readME = File(folder, cacheApptxt)
                val file = File(readME.path)
                val out: BufferedWriter
                try {
                    out = BufferedWriter(FileWriter(file, true), 1024)
                    out.write(writeThis)
                    out.newLine()
                    out.close()
                    Log.d("Output_Success", folder.path)
                } catch (e: Exception) {
                    Log.d("Output_Exception", "$e")
                }
            }
            return folder.path

    }

        override fun onPostExecute(result: String) {
            super.onPostExecute(result)

            if(result.isNotEmpty()){
                //implement an interface or do something
                Log.d("onPostExecuteSuccess", result)
            }else{
                Log.d("onPostExecuteFailure", result)
            }
        }

    }

Oczywiście, jeśli używasz Androida powyżej Api 23, musisz obsłużyć żądanie, aby umożliwić zapis do pamięci urządzenia. Coś takiego

    import android.Manifest
    import android.content.Context
    import android.content.pm.PackageManager
    import android.os.Build
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.app.ActivityCompat
    import androidx.core.content.ContextCompat

    class ReadandWrite {
        private val mREAD = 9
        private val mWRITE = 10
        private var readAndWrite: Boolean = false
        fun readAndwriteStorage(ctx: Context, atividade: AppCompatActivity): Boolean {
            if (Build.VERSION.SDK_INT < 23) {
                readAndWrite = true
            } else {
                val mRead = ContextCompat.checkSelfPermission(ctx, Manifest.permission.READ_EXTERNAL_STORAGE)
                val mWrite = ContextCompat.checkSelfPermission(ctx, Manifest.permission.WRITE_EXTERNAL_STORAGE)

                if (mRead != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(atividade, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), mREAD)
                } else {
                    readAndWrite = true
                }

                if (mWrite != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(atividade, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), mWRITE)
                } else {
                    readAndWrite = true
                }
            }
            return readAndWrite
        }
    }

następnie w działaniu wykonaj połączenie.

  var pathToFileCreated = ""
    val anRW = ReadandWrite().readAndwriteStorage(this,this)
    if(anRW){
        pathToFileCreated =  WriteFile().execute("onTaskComplete").get()
        Log.d("pathToFileCreated",pathToFileCreated)
    }
AllanRibas
źródło
te uprawnienia do przechowywania wewnętrznego są nieprawidłowe.
Lerk
0

Kotlin

class FileReadWriteService {

    private var context:Context? = ContextHolder.instance.appContext

    fun writeFileOnInternalStorage(fileKey: String, sBody: String) {
        val file = File(context?.filesDir, "files")
        try {
            if (!file.exists()) {
                file.mkdir()
            }
            val fileToWrite = File(file, fileKey)
            val writer = FileWriter(fileToWrite)
            writer.append(sBody)
            writer.flush()
            writer.close()
        } catch (e: Exception) {
            Logger.e(classTag, e)
        }
    }

    fun readFileOnInternalStorage(fileKey: String): String {
        val file = File(context?.filesDir, "files")
        var ret = ""
        try {
            if (!file.exists()) {
                return ret
            }
            val fileToRead = File(file, fileKey)
            val reader = FileReader(fileToRead)
            ret = reader.readText()
            reader.close()
        } catch (e: Exception) {
            Logger.e(classTag, e)
        }
        return ret
    }
}
Sazzad Hissain Khan
źródło