Ghi file text vào Internal Storage Android
Internal Storage là bộ nhớ riêng tư của ứng dụng tại /data/data/package.name/files/. Không cần permission, tự động xóa khi uninstall, an toàn cho dữ liệu nhạy cảm.
Bước 1: Tạo dự án
Android Studio → File → New Project.
Bước 2: Giao diện (activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:padding="16dp">
<EditText
android:id="@+id/enterText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nhập nội dung cần lưu"
android:inputType="textMultiLine"
android:minHeight="120dp"
android:gravity="top" />
<Button
android:id="@+id/save"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lưu vào Internal Storage"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
Bước 3: MainActivity.java
package com.example.internalstoragefile;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
Button btnSave;
EditText edtInput;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSave = findViewById(R.id.save);
edtInput = findViewById(R.id.enterText);
btnSave.setOnClickListener(v -> {
String text = edtInput.getText().toString().trim();
if (text.isEmpty()) {
Toast.makeText(this, "Vui lòng nhập nội dung", Toast.LENGTH_SHORT).show();
return;
}
// Thư mục: /data/data/pkg/files/text/
File dir = new File(getFilesDir(), "text");
if (!dir.exists()) {
boolean created = dir.mkdirs();
if (!created) {
Toast.makeText(this, "Không thể tạo thư mục", Toast.LENGTH_SHORT).show();
return;
}
}
// File: /data/data/pkg/files/text/sample.txt
File file = new File(dir, "sample.txt");
try (FileWriter writer = new FileWriter(file)) {
writer.write(text);
writer.flush();
Toast.makeText(this, "Đã lưu thành công!\nĐường dẫn: " + file.getAbsolutePath(), Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "Lỗi ghi file: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}
Bước 4: AndroidManifest.xml - KHÔNG CẦN QUYỀN
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.internalstoragefile">
<!-- Internal Storage KHÔNG cần permission nào -->
<!-- Chỉ cần permission khi truy cập External Storage -->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Chạy và kiểm tra
- Nhập văn bản → nhấn "Lưu".
- Toast hiển thị đường dẫn file đầy đủ.
- Mở Device File Explorer (View → Tool Windows → Device File Explorer).
- Điều hướng:
data → data → com.example.internalstoragefile → files → text → sample.txt - Kéo file ra máy tính để xem nội dung.
Các phương thức File hữu ích
Context context = getApplicationContext();
// Thư mục files gốc: /data/data/pkg/files/
File filesDir = context.getFilesDir();
// Thư mục cache: /data/data/pkg/cache/ (hệ thống có thể xóa khi thiếu dung lượng)
File cacheDir = context.getCacheDir();
// Tạo file con
File file = new File(filesDir, "data.txt");
File fileInSub = new File(filesDir, "subfolder/data.txt");
// Kiểm tra
file.exists()
file.length() // Kích thước byte
file.lastModified() // Thời gian sửa đổi
file.delete() // Xóa file
file.mkdirs() // Tạo thư mục đệ quy
Đọc file đã lưu
private String readFromFile(String fileName) {
File file = new File(getFilesDir(), fileName);
if (!file.exists()) return null;
StringBuilder content = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return content.toString();
}
Ghi file nhị phân (Bitmap, byte[])
private void saveBitmap(Bitmap bitmap, String fileName) {
File file = new File(getFilesDir(), fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
fos.flush();
} catch (IOException e) { e.printStackTrace(); }
}
private Bitmap loadBitmap(String fileName) {
File file = new File(getFilesDir(), fileName);
if (!file.exists()) return null;
return BitmapFactory.decodeFile(file.getAbsolutePath());
}
Internal vs External Storage - Tóm tắt
| Tiêu chí | Internal Storage | External Storage |
|---|---|---|
| Permission | Không cần | Cần (API ≤ 28) |
| Độ an toàn | Cao (private) | Thấp (public) |
| Dung lượng | Nhỏ (~MB-GB) | Lớn (GB) |
| Xóa khi uninstall | Có | Không (trừ app-specific dir) |
| Phù hợp | Settings, token, cache, log | Media, download, share file |
⚠️ Best Practices
- Luôn dùng
try-with-resources(Java 7+) để tự đóng stream. - File I/O lớn → chạy background thread (Coroutine, RxJava, Executor).
- Kiểm tra dung lượng trống:
StatFshoặcgetFreeSpace(). - Dữ liệu cấu trúc phức tạp → dùng JSON (Gson/Moshi) hoặc Protocol Buffers.
- Log file: xoay vòng (rotate) để tránh lấp đầy bộ nhớ.