기기에 데이터 저장
램에서 보조기억장치()로 파일로 데이터를 저장하는 방법
램이 아닌 하드 디스크는 전부 file 형태로 저장되어 있음
① 저장할 값 가져옴
② 내부 저장소(internal Storage)의 전용 공간에 Data.txt 라는 파일에 이 문자열 데이터를 저장하기
-> 파일쪽으로 데이터를 내보내는 스트림 열기 : FileOutputStream
-> 액티비티클래스 안에 이미 내부 저장소의 파일을 여는 기능메소드가 존재함 : openFileOutput
FileOutputStream fos = openFileOutput("Data.txt", MODE_APPEND);
💡 openFileOutput
openFileOutput(저장파일 이름, mode)
- MODE_PRIVATE : 프라이빗 하면서 덮어쓰기
- MODE_APPEND : 프라이빗 하면서 이어붙이기
③ 바이트스트림을 보조문자스트림으로 변환 : PrintWriter
-> FileOutputStream은 바이트 단위로 데이터를 저장해야 하기에 불편함
그래서 문자스트림으로 변환해 여기서 더 나아가서 '보조문자스트림(문장 단위 저장)'을 끄면 더 편함
** 1,2,3 세트임
① 파일 읽어오기 (바이트로 읽어옴) : FileInputStream
② 바이트 스트림 => 문자스트림으로 변환(한글자씩 읽음) : InputStreamReader
③ 문자스트림 -> 보조 문자 스트림으로 변환(한줄 단위로 읽음) : BufferedReader
④ 파일의 끝이 몇문장인지 모르니 문자열 쌓아두는 애 생성 : StringBuffer
⑤ while문으로 파일 읽기 : .readLine()
-> .readLine()은 줄바꿈 문자를 제외하고 읽어옴
-> buffer.append(line+"\n"); //줄바꿈 문자를 어거지로 추가해줘야함
⑥ buffer에 append된 파일 출력
package com.bsj0420.ex54internalstorage;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
public class MainActivity extends AppCompatActivity {
EditText et;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = findViewById(R.id.et);
tv = findViewById(R.id.tv);
findViewById(R.id.btn_save).setOnClickListener(view -> clickSave());
findViewById(R.id.btn_load).setOnClickListener(view -> clickLoad());
}
void clickSave(){
//1. 저장할 값 가져옴
String data = et.getText().toString();
et.setText("");
//내부 저장소(internal Storage)의 전용 공간에 Data.txt 라는 파일에
//이 문자열 데이터를 저장하기
//파일쪽으로 데이터를 내보내는 스트림 열기
//액티비티클래스 안에 이미 내부 저장소의 파일을 여는 기능메소드가 존재함 : openFileOutput
//MODE_PRIVATE : 프라이빗 하면서 덮어쓰기
//MODE_APPEND : 프라이빗 하면서 이어붙이기
try {
//2.
FileOutputStream fos = openFileOutput("Data.txt", MODE_APPEND);
//fos는 바이트 단위로 데이터를 저장해야 하기에 불편함
//그래서 문자스트림으로 변환
//여기서 더 나아가서 '보조문자스트림'을 끄면 더 편함
//FileOutputStream : 파일이 없으면 자동으로 만듦
//3.
PrintWriter writer = new PrintWriter(fos);
writer.println(data);
writer.flush();
writer.close();
tv.setText("SAVED");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
void clickLoad(){
//내부 저장소에 Data.txt 라는 파일에서 데이타 읽어오기
try {
//1. 파일 읽어오기 (바이트로 읽어옴)
FileInputStream fis = openFileInput("Data.txt");
//2. 바이트 스트림 => 문자스트림으로 변환(한글자씩 읽음)
InputStreamReader isr = new InputStreamReader(fis);
//3. 문자스트림 -> 보조 문자 스트림으로 변환(한줄 단위로 읽음)
//1,2,3 세트임
BufferedReader reader = new BufferedReader(isr);
//4. 파일의 끝이 몇문장인지 모르니 문자열 쌓아두는 애 생성
StringBuffer buffer = new StringBuffer();
//5. while문으로 파일 읽기
while (true) {
String line = reader.readLine(); //.readLine()은 줄바꿈 문자를 제외하고 읽어옴
if(line == null) break;
buffer.append(line+"\n"); //줄바꿈 문자를 어거지로 추가해줘야함
}
//6. buffer에 append된 파일 출력
tv.setText(buffer.toString());
} catch (FileNotFoundException e) {
Toast.makeText(this, "해당파일을 찾을 수 없습니다", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
💡 앱 전용 공간 파일 저장 위치
① 외부메모리(SD카드)가 있는지 확인
-> Environment.getExternalStorageState();
② 이 외부메모리의 상태가 연결(mounted) 되어 있지 않은가 확인
-> if(!state.equals(Environment.MEDIA_MOUNTED))
MEDIA_MOUNTED 말고는 아무것도 저장할 수 없는 상태
③ 저장 할 데이터 가져오기
④ 직접 스트림을 열기 위해 파일 객체 생성
-> 내부 저장소와 다르게 액티비티에 스트림 곧바로 열어주는 기능이 없음
4-1) 파일이 저장될 경로 : 앱에게 할당된 개별 영역
-> 디렉토리 목록들을 액티비티한테 얻어옴
File[] dirs = getExternalFilesDirs("MyDir"); //(하위 폴더명)
파일이 저장될 경로 확인
4-2) 파일명과 경로를 결합하여 File 객체를 생성
File file = new File(dirs[0], "Data.txt");
⑤ file과 연결하는 무지개로드 만들기
5-1) 곧바로 문자스트림으로 만들 수 있음
FileWriter fw = new FileWriter(file, true); //true : 이어붙이기 모드
5-2) 문자스트림 -> 문장
PrintWriter writer = new PrintWriter(fw);
① SD카드가 읽을 수 있는 상태인지 확인
② 파일의 경로 찾아오기
③ FileReader() 생성
④ 바이트 -> 한줄씩 : BufferedReader()
⑤ 여러줄 입력 했을 수 있으니 글자 쌓아두기 : StringBuffer()
package com.bsj0420.ex55datastorageexternal;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Environment;
import android.widget.EditText;
import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class MainActivity extends AppCompatActivity {
EditText et;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = findViewById(R.id.et);
tv = findViewById(R.id.tv);
findViewById(R.id.btn_save).setOnClickListener(view -> clickSave());
findViewById(R.id.btn_load).setOnClickListener(view -> clickLoad());
}
void clickSave(){
//1. 외부메모리(SD카드)가 있는지 확인
String state = Environment.getExternalStorageState();
//2. 이 외부메모리의 상태가 연결(mounted) 되어 있지 않은가 확인
if(!(state.equals(Environment.MEDIA_MOUNTED))){
Snackbar.make(tv,"SD card is not mounted",Snackbar.LENGTH_LONG).show();
return; //작업 종료
}
//3. 저장 할 데이터 가져오기
String data = et.getText().toString();
et.setText("");
//4.
//"Data.txt" 라는 파일에 데이터 저장
//내부 저장소와 다르게 액티비티에 스트림 곧바로 열어주는 기능이 없음
//그래서 직접 스트림을 열기 위해 파일 객체 생성
//4-1)
//파일이 저장될 경로 : 앱에게 할당된 개별 영역
//디렉토리 목록들을 액티비티한테 얻어옴
File[] dirs = getExternalFilesDirs("MyDir"); //하위 폴더명
//경로 확인용 for문
String s="";
for(File f : dirs) {
s = s+ f.getPath() + "\n";
}
tv.setText(s); //경로 확인
//4-2)
//여러 경로중 첫번째가 보통 SDcard
//파일명과 경로를 결합하여 File 객체를 생성
File file = new File(dirs[0], "Data.txt");
//5.
//file과 연결하는 무지개로드 만들기
//곧바로 문자스트림으로 만들 수 있음
try {
//5-1)
FileWriter fw = new FileWriter(file, true); //true : 이어붙이기 모드
//5-2)
PrintWriter writer = new PrintWriter(fw);
writer.println(data);
writer.flush();
writer.close();
tv.setText("SAVED");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
void clickLoad(){
//1. SD카드가 읽을 수 있는 상태인지 확인
String state = Environment.getExternalStorageState();
if(state.equals(Environment.MEDIA_MOUNTED)||state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
//읽을 수 있는 상태
//2. 파일의 경로 찾아오기
File[] dirs = getExternalFilesDirs("MyDir");
File file = new File(dirs[0], "Data.txt"); //파일 객체를 만들어서 정확한 위치 찾아주는 작업
try {
//3. FileReader() 생성
FileReader fr = new FileReader(file);
//4. 바이트 -> 한줄씩 : BufferedReader()
BufferedReader reader = new BufferedReader(fr);
//5. 여러줄 입력 했을 수 있으니 글자 쌓아두기 : StringBuffer()
StringBuffer buffer = new StringBuffer();
while (true) {
String line = reader.readLine();
if(line == null) break;
buffer.append(line + "\n");
}
tv.setText(buffer.toString());
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
① 저장 할 데이터 얻어오기
② "Data.xml" 파일에 데이터를 SharedPreferences로 저장하기 위해 객체 '얻어'오기 : getSharedPreferences()
📢 getPreferences() vs getSharedPreferences()
getPreferences() : 이 액티비티에서만 쓸수 있음
getSharedPreferences(파일이름,모드) : 앱 전체에서 쓸 수 있음
모드는 무조건 MODE_PRIVATE
③ 저장작업
④ 작업 완료 : commit() - 꼭!!
① 저장한 파일 객체 SharedPreferences한테 '얻어'오기
② 자료형 기준으로 get : //get자료형(식별자, 디폴트 밸류)
③ 읽어온 값 확인
package com.bsj0420.ex56datastoragesharedpreference;
import androidx.appcompat.app.AppCompatActivity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
EditText etName, etAge;
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etName = findViewById(R.id.et_name);
etAge = findViewById(R.id.et_age);
tv = findViewById(R.id.tv);
findViewById(R.id.btn_save).setOnClickListener(view -> clickSave());
findViewById(R.id.btn_load).setOnClickListener(view -> clickLoad());
}
void clickSave(){
//1.저장 할 데이터 얻어오기
String name = etName.getText().toString();
int age = Integer.parseInt(etAge.getText().toString());
//2. SharedPreferences로 저장
// "Data.xml" 파일에 데이터를 저장하기 위해 객체 '얻어'오기
SharedPreferences pref = getSharedPreferences("Data",MODE_PRIVATE);
//getPreferences() : 이 액티비티에서만 쓸수 있음
//getSharedPreferences() : 앱 전체에서 쓸 수 있음
//모드는 무조건 MODE_PRIVATE
//3. 저장작업
//3-1.작성자 생성 : edit()
SharedPreferences.Editor editor =pref.edit(); //작성자가 리턴됨
//3-2. 작성자에 값 저장 : editor.putString(식별자, 값)
editor.putString("name",name);
editor.putInt("age",age);
//4. 작업 완료 - 꼭!!
editor.commit(); // 내부적으로 트랜잭션 하고 있음
}
void clickLoad(){
//1. 저장한 파일 객체 SharedPreferences한테 '얻어'오기
SharedPreferences pref = getSharedPreferences("Data",MODE_PRIVATE);
//2. 자료형 기준으로 get : //get자료형(식별자, 디폴트 밸류)
String name = pref.getString("name","무(無)명");
int age = pref.getInt("age",0);
//3. 확인
tv.setText(name +" : "+age);
}
void clickClear(){
SharedPreferences pref = getSharedPreferences("Data",MODE_PRIVATE);
SharedPreferences.Editor editor =pref.edit();
editor.clear().commit()
}
}
🧨 단점
SharedPreference는 데이터가 덮어쓰기 됨
📢 만들어진 DB파일에 작업할 때 키워드
.execSQL() : 쿼리 작업 중 리턴값이 없는 것들 : c,u,d 작업
.rawQuery() : 값을 리턴 받아야 하는 것 : r 작업
① text.db 라는 이름으로 데이터베이스 파일을 열거나 또는 생성
-> openOrCreateDatabase(파일명, MODE_PRIVATE 밖에 안됨, 값 읽어올떄 커스텀 하느라 쓰는것)
-> 이 메소드를 실행하면 text.db를 제어할 수 있는 능력을 가진 객체가 리턴됨 : SQLiteDatabase
② 만들어진 DB파일에 테이블(표)를 생성하는 작업
-> SQL언어를 이용해서 원하는 명령어를 Datbase에 수행함
🔨 테이블 생성 쿼리
"CREATE TABLE 테이블이름(id INT(10), name VARCHAR(20), msg TEXT)"
- CREATE TABLE IF NOT EXISTS : 테이블이 존재하지 않으면 만들어라
- VARCHAR : 변할 수 있는 CHAR
- 컬럼명에 no는 예약어라 쓸수 없음
//1. 데이터 저장 할 테이블 만들기
// text.db 라는 이름으로 데이터베이스 파일을 열거나 또는 생성
// -> openOrCreateDatabase(파일명, MODE_PRIVATE 밖에 안됨, 값 읽어올떄 커스텀 하느라 쓰는것)
//이 메소드를 실행하면 text.db를 제어할 수 있는 능력을 가진 객체가 리턴됨 : SQLiteDatabase
sqLiteDatabase = openOrCreateDatabase("text", MODE_PRIVATE, null);
//2. 만들어진 DB파일에 테이블(표)를 생성하는 작업
//SQL언어를 이용해서 원하는 명령어를 Datbase에 수행함
// CREATE TABLE IF NOT EXISTS : 테이블이 존재하지 않으면 만들어라
sqLiteDatabase.execSQL("CREATE TABLE IF NOT EXISTS member(num INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(20) NOT NULL,age INTEGER, email TEXT)");
☝ 만든 테이블 확인 (App inspection : 앱이 실행중일때만 보임)
value를 넣을 떈 반드시 'value' 작은 따음표 안에 받아야함!!!
🔨 isnsert 쿼리
".execSQL(INSERT INTO table_name (column1, column2, column3) VALUES ('"+value1+"', '"+value2+"', '"+value3+"')")
테이블의 모든 데이터들을 검색하여 가져오기
//select : rawQuery()
void clickSelectAll(){
//member 테이블의 모든 데이터들을 검색하여 가져오기
//1.
//테이블을 select 하면 select 한 애를 새로운 테이블로 만들고 cutsor로 읽음
Cursor cursor = sqLiteDatabase.rawQuery("SELECT * FROM member", null);
//rawQuery("SELECT * FROM 테이블명", where절 없으면 null);
if(cursor == null) return; //cursor가 null이란것은 참조변수만 만들어지고 값은 없다는 것
//2.총 줄(row : 레코드) 수 : 레이어를 끝까지 읽어오기
int rowCnt = cursor.getCount();
//3.첫번째 레코드로 이동
cursor.moveToFirst();
//4. 데이터를 쌓아놓기 위한 StringBuffer
StringBuffer buffer = new StringBuffer();
//5. for문을 이용해 레코드 읽는다
for(int i=0; i< rowCnt; i++) {
int num = cursor.getInt(0);
String name = cursor.getString(1);
int age = cursor.getInt(2);
String email = cursor.getString(3);
buffer.append(num + " "+ name+ " "+ age + " "+ email + "\n");
cursor.moveToNext(); //다음 레코드로 이동
}
//6. 알럿 화면에 결과 보려주기
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(buffer.toString());
builder.create().show();
}
특정 값만 찾아오기
//특정 값만 찾아오기
void clickSelect(){
//1. where절 조건용 변수
String name = etName.getText().toString();
//2. 테이블을 select 하면 select 한 애를 새로운 테이블로 만들고 cutsor로 읽음 : Cursor = .rawQuery()
Cursor cursor = sqLiteDatabase.rawQuery("SELECT name,age FROM member WHERE name=?",new String[]{name});
if(cursor == null) return; //커서에 읽을 값 없으면 함수 종료해라
//3. 레이어를 끝까지 읽어오기 위해 총 레코드 수 찾기
int rowCnt = cursor.getCount();
//4. 커서를 첫번째 로우로 이동
cursor.moveToFirst();
//5. 데이터를 쌓아놓기 위한 StringBuffer (보통은 ArrayList에 저장)
StringBuffer buffer = new StringBuffer();
//6. for문을 이용해 레코드 읽는다
for(int i=0; i< rowCnt; i++) {
String name2 = cursor.getString(0); //resultSet 기준으로 index번호 쓴다
int age = cursor.getInt(1);
buffer.append(name+ " "+ age + " "+ "\n");
cursor.moveToNext();
}
//7. 화면출력
new AlertDialog.Builder(this).setMessage(buffer.toString()).create().show();
}
select 한 컬럼 기준으로 새로 테이블을 만들고 cursor가 가르킴
🔨 update 쿼리
".execSQL(UPDATE table SET column1 = value, column2 = value2 WHERE column = ? ", new String[]{value})
🔨 delete 쿼리
" .execSQL(DELETE FROM table WHERE column =? ", new String[]{value})