일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- 가명정보처리
- 한국정보보호산업협회
- 확장 유클리드 알고리즘
- 무료교육
- node.js
- 모듈러 연산
- 백엔드입문
- 디오판투스 알고리즘
- 한국정보보호산업협회기자단
- 동적타이핑
- 개인정보보호위원회
- 포너블
- 개인정보보호
- 마감임박
- 곱셈 암호
- package-lock.json
- 백엔드
- package.json
- 개인정보보호교육
- 웹 프레임워크
- 호이스팅
- arrow function
- 유클리드_알고리즘
- 국가인적자원개발컨소시엄
- function scope
- 덧셈 암호
- pwnable.tw
- 개인정보안전성
- Writeup
- 한국산업인력공단
- Today
- Total
짱짱해커가 되고 싶은 나
08-1. 파일 처리 본문
안드로이드 파일 처리 방법(제한된 폴더/SD 카드 등에서만 가능)
- Java에서 제공되는 파일 관련 클래스 사용
- 안드로이드에서 제공되는 파일 관련 클래스 사용
* 내장 메모리 파일 처리
ex) 앱을 종료했다가 다음에 다시 시작했을 때 사용했던 곳부터 이어서 작업하고 싶을 때 내장 메모리에 파일을 저장하고 읽어오는 방식
내장 메모리 : /data/data/패키지명/files 에 위치
(응용 프로그램마다 고유의 저장 공간 존재)
<activity_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="내장 메모리에 파일 쓰기"
android:id="@+id/btnWrite"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="내장 메모리에서 파일 읽기"
android:id="@+id/btnRead"/>
</LinearLayout>
<MainActivity.java>
package com.example.toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btnRead, btnWrite;
btnRead = (Button)findViewById(R.id.btnRead);
btnWrite = (Button)findViewById(R.id.btnWrite);
btnWrite.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
FileOutputStream outFs = openFileOutput("file.txt", Context.MODE_PRIVATE);
String str = "쿡북 안드로이드";
outFs.write(str.getBytes());
outFs.close();
Toast.makeText(getApplicationContext(), "file.txt가 생성됨", Toast.LENGTH_SHORT).show();
}catch(IOException e){
}
}
});
btnRead.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
FileInputStream inFs = openFileInput("file.txt");
byte[] txt = new byte[30];
inFs.read(txt);
String str = new String(txt);
Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
}catch(IOException e){
Toast.makeText(getApplicationContext(), "파일 없음", Toast.LENGTH_SHORT).show();
}
}
});
}
}
파일 모드에서 쓰기는 MODE_PRIVATE, MODE_APPEND가 가능하다.
프로젝트1: 일기장 앱
날짜를 선택했을 때 그 날짜의 일기가 없으면 새로 작성, 있으면 보여주기
- DatePicker 1개
- EditText 1개
- Button 1개
<activity_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<DatePicker
android:layout_weight="1"
android:layout_marginTop="60dp"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/datePicker"
android:datePickerMode="spinner"
android:calendarViewShown="false"/>
<EditText
android:padding="5dp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/getDiary"
android:background="#F8E0E6"
android:textColor="#000000"
android:lines="8"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn"
android:enabled="false"
android:text="Button"/>
</LinearLayout>
<MainActivity.java>
package com.example.toast;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity {
DatePicker datePicker;
EditText editText;
Button btn;
String fileName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setTitle("간단 일기장");
datePicker = (DatePicker)findViewById(R.id.datePicker);
editText = (EditText)findViewById(R.id.getDiary);
btn = (Button)findViewById(R.id.btn);
Calendar cal = Calendar.getInstance();
int cYear = cal.get(Calendar.YEAR);
int cMont = cal.get(Calendar.MONTH);
int cDay = cal.get(Calendar.DAY_OF_MONTH);
fileName = Integer.toString(cYear) + "_" + Integer.toString(cMont+1) + "_" +
Integer.toString(cDay) + ".txt";
String initStr = readDiary(fileName);
editText.setText(initStr);
btn.setEnabled(true);
datePicker.init(cYear, cMont, cDay, new DatePicker.OnDateChangedListener() {
@Override
public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
fileName = Integer.toString(year) + "_" + Integer.toString(monthOfYear+1) + "_" +
Integer.toString(dayOfMonth) + ".txt";
String str = readDiary(fileName);
editText.setText(str);
btn.setEnabled(true);
}
});
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
try{
FileOutputStream outFs = openFileOutput(fileName, Context.MODE_PRIVATE);
String str = editText.getText().toString();
outFs.write(str.getBytes());
outFs.close();
Toast.makeText(getApplicationContext(), fileName + "이 저장됨", Toast.LENGTH_SHORT).show();
}catch(IOException e){
}
}
});
}
String readDiary(String fName){
String diaryStr = null;
FileInputStream inFs;
try{
inFs = openFileInput(fName);
byte[] txt = new byte[500];
inFs.read(txt);
inFs.close();
diaryStr = (new String(txt).trim());
btn.setText("수정하기");
} catch (IOException e){
editText.setHint("일기 없음");
btn.setText("새로 저장");
}
return diaryStr;
}
}
이렇게 저장된 파일을 확인하려면 장치 연결/AVD 실행 상태에서 Device File Explorer를 들어간다.
그리고 내장 메모리 파일 위치에 가면 만든 파일이 있는 것을 확인할 수 있다.
* raw 폴더 파일 처리
프로젝트의 /res/raw 폴더에 필요한 파일을 저장해서 사용할 수 있다. (raw 폴더를 생성할때 resource type도 raw)
읽기 전용으로만 사용 가능하고 쓰기는 내장 메모리나 SD 카드를 사용해야 한다.
package com.example.toast;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.io.InputStream;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button)findViewById(R.id.btn);
final EditText editText = (EditText)findViewById(R.id.editText);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try{
InputStream inputStream = getResources().openRawResource(R.raw.raw_test);
byte[] txt = new byte[inputStream.available()];
inputStream.read(txt);
editText.setText(new String(txt));
inputStream.close();
}catch (IOException e){
}
}
});
}
}
- openRawResource() : /res/raw/ 리소스를 읽기용으로 열고 InputStream 으로 반환한다.
- inputStream.availabe() : 입력 스트림에서 읽을 수 있는 바이트 수를 반환한다 (== 파일크기)
* SD 카드 파일 처리
SD 카드에서 파일을 읽기 위해 Device File Explorer에서 /sdcard 폴더 또는 /storage/emulator/0 폴더에 텍스트 파일을 올린다.
(AVD에서 SD 카드의 경로는 절대적인 것이 아니며 SDK버전에 따라 달라질 수 있다.)
AndroidMainfest.xml에 외부 저장 매체 쓰기 권한과 속성을 추가한다.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:requestLegacyExternalStorage="true"
package com.example.toast;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import java.io.FileInputStream;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button)findViewById(R.id.btn);
final EditText editText = (EditText)findViewById(R.id.editText);
ActivityCompat.requestPermissions(this, new String[]{
android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, MODE_PRIVATE);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
try{
FileInputStream inFs = new FileInputStream("/sdcard/sd_test.txt");
byte[] txt = new byte[inFs.available()];
inFs.read(txt);
editText.setText(new String(txt));
inFs.close();
}catch(IOException e){
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
});
}
}
android 6.0부터는 보안 모델이 강화되어 ActivityCompat.requctPermission()를 이용해 각 앱마다 파일 등에 엑세스 할 수 있도록 코딩해야한다. 이 메소드를 사용하면 아래의 사진처럼 사용자가 거부/허용 할 수 있는 대화상자가 나오고 허용을 클랙해야만 파일 등에 접근이 가능하다.
이걸 코딩할 때 원래 AVD 11을 썼었는데 11에서는 이렇게 해도 접근 권한이 안되는 것이다 ㅠㅠ
그래서 AVD를 10으로 바꿨더니 정상적으로 작동했다.
sd카드에 디렉터리를 생성/삭제/읽기
<AndroidMainfest.xml>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.file">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:requestLegacyExternalStorage="true"
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/Theme.File">
<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>
<activity_main.xml>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:padding="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="SD 카드에 디렉터리 생성"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:text="SD 카드에 디렉터리 삭제"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn3"
android:text="시스템 폴더/파일 등록"/>
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/editText"/>
</LinearLayout>
<MainActivity.java>
package com.example.file;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
public class MainActivity extends AppCompatActivity {
Button btn1, btn2, btn3;
EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, MODE_PRIVATE);
btn1 = (Button)findViewById(R.id.btn1);
btn2 = (Button)findViewById(R.id.btn2);
btn3 = (Button)findViewById(R.id.btn3);
editText = (EditText)findViewById(R.id.editText);
final String strDpatch = Environment.getExternalStorageDirectory().getAbsolutePath();
final File myDir = new File(strDpatch + "/mydir");
btn1.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v)
{
try{
myDir.mkdir();
Toast.makeText(getApplicationContext(), myDir.getAbsolutePath(), Toast.LENGTH_SHORT).show();
}catch(Exception e){
e.printStackTrace();
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
try{
myDir.delete();
Toast.makeText(getApplicationContext(), myDir.getAbsolutePath(), Toast.LENGTH_LONG).show();
} catch (Exception e){
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
});
btn3.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
editText.setText(null);
String sysDir = Environment.getRootDirectory().getAbsolutePath();
File[] sysFiles = (new File(sysDir).listFiles());
File[] sdFiles = (new File(strDpatch).listFiles());
String strFname;
for(int i=0; i<sdFiles.length; i++){
if(sdFiles[i].isDirectory() == true)
strFname = "<폴더> " + sdFiles[i].toString();
else
strFname = "<파일> " + sdFiles[i].toString();
editText.setText(editText.getText() + "\n" + strFname);
}
}
});
}
}
sd 카드 디렉터리가 잘 생성됐나 확인하려고 코드를 조금 변경했는데 만약 시스템 폴더를 확인하고 싶으면 sysFiles 변수로 뽑으면 된다. 시스템 디렉토리는 RootDirectory의 위치를 찾으면 된다.
'모바일' 카테고리의 다른 글
09-1. 그래픽 (0) | 2021.02.23 |
---|---|
08-2. SD 카드 폴더/파일 처리 연습 (0) | 2021.02.22 |
07-3. 메뉴/토스트/다이얼로그 연습 (0) | 2021.02.20 |
07-2. 토스트 & 대화상자 (0) | 2021.02.20 |
07-1. 메뉴 (0) | 2021.02.20 |