Development/Android

21. 파일 입출력

궁선이 2018. 5. 5. 01:46

이번 포스팅은 앱을 앱답게 만드는 기능입니다.

스마트폰 내부에 파일의 형태로 데이터를 저장시킴으로써
데이터의 저장과 불러오기가 가능합니다.

안드로이드에서의 파일입출력은 자바와 비슷하게 이루어집니다.
좀 더 자세히, 효율적으로 사용을 하고 싶다면
자바의 파일입출력을 먼저 공부하시기 바랍니다.

Byte단위 처리
FileInputStream / FileOutputStream 클래스
BufferedInputStream / BufferedOutputStream 클래스

문자 단위 처리
FileReader / FileWriter 클래스
BufferedReader / BufferedWriter 클래스

위 클래스 들을 주로 사용하여 이루어집니다.

이 포스팅에서는 크게 3가지의 파일입출력을 다룰 것 입니다.

1. 내장메모리 파일 입출력
2. Raw 폴더 파일입출력 (읽기전용)
3. 외장메모리(SD card) 파일입출력 및 파일입출력

1. 내장메모리 파일입출력

아마 가장 많이 사용될 기능일 것입니다.

내장메모리의 파일 저장위치는

/data/data/패키지명/
의 위치에 저장됩니다.

구버전의 안드로이드에서는 직접 해당 파일에 접근이 가능했으나
현재는 막아놨습니다. 터미널에서 직접 접근이 가능하나 이 포스팅에서 다루지 않겠습니다.

파일을 저장하는 경로를 가져오는 함수는

getFileDir();

Cache File을 저장하는 경로를 가져오는 함수는

getCacheDir();

내장메모리에서 파일 읽기

쉬운 코드이니 쉽게 분석하실 수 있을 것입니다.
핵심은 FileReader을 호출하여 객체를 BufferedReader에 넘겨주는 것입니다.

try{ BufferedReader br = new BufferedReader(new FileReader(getFilesDir() + "buffer.txt")); String readStr = ""; String str = null; while((str = br.readLine())!= null) readStr += str + "\n"; br.close(); Toast.makeText(this,readStr.substring(0,readStr.length()-1),Toast.LENGTH_SHORT).show(); }catch(FileNotFoundException e){ e.printStackTrace(); Toast.makeText(this,"File not found",Toast.LENGTH_SHORT).show(); } catch(IOException e){ e.printStackTrace(); }
내장메모리에 파일 쓰기

FileWriter의 두번째 인자는 인자를 사용을 안하시고 경로만 사용하여 생성하거나
false값을 사용할경우 파일을 초기화하고 백지상태에서 다시 작성합니다.
true일 경우 기존 파일의 끝에서 이어서 작성합니다.

try{ BufferedWriter bw = new BufferedWriter(new FileWriter(getFilesDir() + "buffer.txt",true)); bw.write(""); bw.newLine(); bw.close(); Toast.makeText(this,"저장완료",Toast.LENGTH_SHORT).show(); }catch(IOException e){ e.printStackTrace(); Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); }
2.Raw폴더에서 파일 읽기.

raw폴더는 읽기전용 폴더이며 안드로이드 스튜디오에서 앱을 만들 때에
raw폴더를 생성하여 데이터를 넣어 주는 방식입니다.

먼저 안드로이드 스튜디오 좌측의 디렉토리 목록에서
res폴더의 하위에 raw폴더를 생성하여 줍니다.
그리고 about.txt를 생성하여 문자를 저장하여 줍니다.

그리고 호출은

InputStream is = getResources().openRawSource(R.raw.about);

위와 같은 형태로 스트림을 생성하여 줍니다.

코드를 보겠습니다.
about.txt파일을 읽는 경우입니다.

try { InputStream is = getResources().openRawResource(R.raw.about); byte[] readStr = new byte[is.available()]; is.read(readStr); is.close(); Toast.makeText(this, new String(readStr), Toast.LENGTH_SHORT).show(); } catch (IOException e) { e.printStackTrace(); }


3. 외부메모리 파일입출력 및 디렉토리 생성

안드로이드 23부터는 외부메모리 접근에 위험접근을 부여하여
사용자에게 접근을 허락받아야 합니다.

먼저 AndroidManifest에서 Permission을 등록하여 줍니다.

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


다음 두 함수를 작성하여 onCreate시에 checkPermission()을 호출하여 줍니다.

public void checkPermission(){ int permissioninfo = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE); if(permissioninfo == PackageManager.PERMISSION_GRANTED){ Toast.makeText(getApplicationContext(),"SDCard 쓰기 권한 있음",Toast.LENGTH_SHORT).show(); }else{ if(ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.WRITE_EXTERNAL_STORAGE)){ Toast.makeText(getApplicationContext(),"권한의 필요성 설명",Toast.LENGTH_SHORT).show(); }else{ ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},100); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { String str = null; if(requestCode == 100){ if(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) str = "SD Card 쓰기권한 승인"; else str = "SD Card 쓰기권한 거부"; Toast.makeText(this,str,Toast.LENGTH_SHORT).show(); } super.onRequestPermissionsResult(requestCode, permissions, grantResults); }

그리고 편의를 위해 외부메모리의 경로를 가져오는 함수를 제작하겠습니다.

SD card 메모리가 있는경우 사용이 가능하며 없는 경우 내부메모리에 저장합니다.
핸드폰 버전에 따라 저장위치가 달라지며 사용권한을 획득했다는 전제하에 기능이 작동합니다.

public String getExternalPath(){ String sdPath = ""; String ext = Environment.getExternalStorageState(); if(ext.equals(Environment.MEDIA_MOUNTED)){ sdPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/"; }else{ sdPath = getFilesDir() + ""; Toast.makeText(getApplicationContext(),sdPath,Toast.LENGTH_SHORT).show(); } return sdPath; }
외부 메모리 파일 읽기
try{ String path = getExternalPath(); BufferedReader br = new BufferedReader(new FileReader(path + "test.txt")); String readStr = ""; String str = null; while((str = br.readLine())!= null) readStr += str + "\n"; br.close(); Toast.makeText(this,readStr.substring(0,readStr.length()-1),Toast.LENGTH_SHORT).show(); }catch(FileNotFoundException e){ e.printStackTrace(); Toast.makeText(this,"File not found",Toast.LENGTH_SHORT).show(); } catch(IOException e){ e.printStackTrace(); }
외부메모리 파일 쓰기
try{ String path = getExternalPath(); BufferedWriter bw = new BufferedWriter(new FileWriter(path + "test.txt",true)); bw.write("SD카드 쓰기"); bw.newLine(); bw.close(); Toast.makeText(this,"SD 저장완료",Toast.LENGTH_SHORT).show(); }catch(IOException e){ e.printStackTrace(); Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); }
외부메모리 디렉토리 생성
String path = getExternalPath(); File file = new File(path + "mydir3"); file.mkdir(); String msg = "디렉토리 생성"; if(file.isDirectory() == false) msg = "디렉터리 생성 오류"; Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();
외부메모리 디렉토리 목록 가져오기
String path = getExternalPath(); File[] files = new File(path).listFiles(); String str = ""; for(File f:files){ str += f.getName() +"\n"; } et.setText(str); // EditText et