Friday 29 August 2014

Đọc ghi file cơ bản trong Android

Có thể nói việc lưu trữ dữ liệu dữ liệu là một việc làm phổ biến trong Android. Vì vậy Android có khá nhiều cách cho phép chúng ta lưu trữ dữ liệu, với từng công việc khác nhau mà chúng ta lựa chọn sao cho phù hợp với yêu cầu.
Việc lưu trữ dữ liệu trong Android bao gồm những cách phổ biến sau

  1. Lưu file trong file xml khi bạn cần làm chức năng setting cho máy, hay chỉ cần ghi những dữ liệu nhỏ(sử dụng SharedPreferences)
  2. Lưu trữ bằng database sử dụng SQLite mà Android hộ trợ.
  3. Tiếp đến là việc đọc/file trong bộ nhớ máy hay ngoài thẻ nhớ.
Trong bài viết này mình sẽ giới thiệu cho các bạn các đọc ghi file trong bộ nhớ máy một cách trực tiếp. Sau bài viết này các bạn hoàn toàn có thể tạo ra một phần mềm ghi chú đơn giản cho riêng mình ở mức độ đơn giản nhất.

Trước tiên các bạn cần tạo một new Project
ở đây mình đặt tên là ReadWriteFile. Để tiện cho các bạn theo dõi quá trình làm từ giờ mình sẽ show cấu trúc thư mục và các file của project mình làm để các bạn tiện theo dõi hơn.

Đơn giản chúng ta chỉ cần một new Project với nhưng folder và layout mặc định khi tạo một là đủ.
Để bắt đầu trước tiên các bạn cần tạo môt layout với các trường như sau

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.readwritefile.MainActivity" >


    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:gravity="top"
        android:minLines="5"
        android:inputType="textMultiLine" >


        <requestFocus />
    </EditText>


    <Button
        android:id="@+id/btnSave"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/editText"
        android:layout_centerHorizontal="true"
        android:text="Save File" />


    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btnSave"
        android:text="Load File" />


</RelativeLayout>

Nếu muốn nhanh các bạn có thể kéo thả các View vào trong Layout trước và chúng ta chỉnh sửa ở file xml sau, với RelativeLayout như ở những bài trước mình nó nó có thể được điều chỉnh bằng cách kéo thả khá dễ dàng, nhưng mình vẫn khuyên các bạn nên hand code để chúng ta nhớ và nâng cao kỹ năng thao tác.
Sau khi tạo xong chúng ta sẽ được giao diện như sau.

Tiếp tới các bạn hãy quay trở lại file MainActivity.java nơi chúng ta sẽ xử lý để thao tác dữ liệu. Trước khi code xử lý việc đọc ghi file mình sẽ giới thiệu qua đọc ghi file trong Android. Nếu các bạn đã làm đọc ghi file trong Java rồi thì việc đọc ghi file trong Android hoàn toàn tương tự nó không khác nhiều lắm. Vẫn sử dụng các đối tượng đọc ghi file của Java để thao tác bình thường. Trong Android chung cung cấp cho chúng ta 2 phương thức cơ bản để đọc ghi file là openFileOutput và openFileInput. Chi tiết hơn về 2 phương thức này các bạn có thể đọc tại đây. Trong file MainActivity.java sẽ có nội dung như sau

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;


import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;




public class MainActivity extends Activity {


private EditText editText;
private Button btnSave;
private Button btnLoad;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.editText = (EditText) findViewById(R.id.editText);
        this.btnSave = (Button) findViewById(R.id.btnSave);
        this.btnLoad = (Button) findViewById(R.id.btnLoad);
        
        this.btnSave.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
saveFile();
}
});
        
        this.btnLoad.setOnClickListener(new View.OnClickListener() {

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


    
    private void saveFile() {
    BufferedWriter writer = null;
    try {
FileOutputStream fileOutputStream = openFileOutput("test_file.txt", Context.MODE_WORLD_READABLE);
String data = editText.getText().toString();
writer = new BufferedWriter(new OutputStreamWriter(fileOutputStream));
writer.write(data);
writer.flush();
this.editText.setText("");
Toast.makeText(this, "Save file sucess", Toast.LENGTH_SHORT).show();
    } catch (FileNotFoundException e) {
// TODO Auto-genered catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
System.err.println("Error save file because : ");
e.printStackTrace();
} finally {
if (writer != null) {
try {
writer.close();//Dam bao viec ghi file thanh cong
} catch (IOException e) {
// TODO Auto-generated catch block
System.err.println("Error close writer");
e.printStackTrace();
}
}
}
   
    }
    
    private void loadFile() {
    BufferedReader reader = null;
    try {
FileInputStream fileInputStream = openFileInput("test_file.txt");
reader = new BufferedReader(new InputStreamReader(fileInputStream));
StringBuffer stringBuffer = new StringBuffer();
String tempStr = "";
while ((tempStr = reader.readLine()) != null) {
stringBuffer.append(tempStr);
}

this.editText.setText(stringBuffer.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
System.err.println("Error read file");
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
System.err.println("Error close reader");
e.printStackTrace();
}
}
}
    }


Ở đây mình sử dụng 2 đối tượng của Java là BufferedReader và BufferedWriter để làm nhiệm vụ đọc ghi file trong chương trình này đây là thói quen sử dụng(nó có ưu nhược điểm riêng-các bạn hãy tìm hiểu, nhưng khi lựa chọn phần chính là ưu tiên tốc độ xử lý, sát với việc đọc ghi stream tốc độ sẽ nhanh hơn còn với 2 đối tượng mình sẽ dụng nó gần như là tầng cao nhất do vậy sẽ trải qua rất nhiều bước convert do vậy nó sẽ không phải là tối ưu cho mặt tốc độ), như đã nói ban đầu các bạn có thể sử dụng rất nhiều đối tượng trong Android khác như FileWriter hay InputStreamReader/OutputStreamWriter để thao tác đọc ghi file trong Android. Với phương thức saveFile mình sẽ tạo một file có tên là test_file.txt với chế độ ghi file có thể đọc. Tiếp đó là các thao tác file như trong ngôn ngữ Java. Để ghi file các bạn cần getText của editText để lấy dữ liệu, hãy nhớ rằng bạn cần đóng file để hoàn thành việc ghi file, không việc ghi file có thể lỗi, tốt hơn cả các bạn hãy đẩy toàn bộ dữ liệu ra khỏi bộ nhớ đệm bằng phương thức flush(); trước khi gọi close()  khi đóng file trong finally. Đọc xong file các bạn cũng nên nhớ đóng file lại để tránh leak memory-tài nguyên trong máy, giúp chương trình bạn hoạt động tốt hơn.

Sau khi hoàn thành 2 phương thức trên các bạn hãy bắt sự kiện cho 2 button btnSave và btnLoad tương ứng và gọi các phương thức saveFile và loadFile tương ứng trong sự kiện click.

Còn đây là kết quả khi chúng ta chạy chương trình
Nhập một đoạn text


Ghi file thành công


và sau khi nhấn button Load file chúng ta được



Vậy là bài hướng dẫn của mình tới đây là kết thúc, hãy comment phía dưới bài viết này nếu bạn không hiểu hay có thắc mắc gì. Nếu có ích hãy chia sẻ cho mọi người nhé


4 comments :

  1. cho hỏi file ghi xong được lưu ở đâu và khi load file có thể tùy chọn file txt bất kì được k?

    ReplyDelete
  2. cho hỏi file ghi xong được lưu ở đâu và khi load file có thể tùy chọn file txt bất kì được k?

    ReplyDelete
  3. Khi chạy, app sẽ tự động tạo ra 1 folder "files" trong source của app và sẽ chứa các file trong đó, khi gọi file bằng openFileInput (), app cũng sẽ tự động vào folder "files" để tìm file đó gọi ra để đọc.
    Bạn có thể kiểm nghiệm bằng cách run app trong máy smartphone của mình, lưu file xong vào mục root/data/data/"tên package của app" bạn sẽ thấy folder "files". Có thể máy cần được root.

    ReplyDelete
  4. Cho e hỏi cách nào để duyệt toàn bộ file trong bộ nhớ vậy ạ, chẳng hạn như tìm toàn bộ ảnh có đuôi .jpg

    ReplyDelete