[베다니 도서관] 3. 파일 불러와 파싱



저장소 접근 권한을 획득했으면 이제 파일을 가져와서 파싱을 할 차례이다.
파싱 기준은 책번호 - 책이름 - 위치 - 날짜 - 비고 이렇게 5가지로 나눈다.
일단 저장소에 있는 파일 중에 csv 파일을 가져와야하는데 2가지 방법으로 생각해봤다.
  1. csv 파일을 전부 찾아서 목록에 띄우고, 그 중에서 올바른 파일을 사용자가 직접 고르기.
  2. 파일 탐색기를 구현해 사용자가 직접 가져오기.
원래는 두번째 방법을 생각했지만, 굳이 탐색기까지 써서 가져올 필요가 있나? 그냥 csv만 가져오면 되는데? 가져오려는 확장자가 한두개보다 많거나 찾고자하는 확장자를 가진 파일의 수가 너무 많을 때에는 파일 탐색기가 유리하겠지만, csv는 특별한 경우가 아니면 잘 쓰지 않을테고, 상업용이나 공용으로 쓸 목적이 아닌 필자가 쓰려는 용도이기 때문에 굳이 파일 탐색기를 구현할 필요는 없다고 판단했다. 따라서 첫번째 방법을 고르자.


1. 파일 찾기

일단 파싱을 하기 위해선 당연히 파일을 찾아야한다. (파싱을 할 수 있는지의 여부 확인은 뒤에 나올 것이다.) 아래와 같은 방식으로 구현한다.


방법

  • 매개변수로 받아오는 File의 모든 파일들을 files에 저장하고 files가 null일 때까지 전부 탐색해준다. 
  • 탐색하는 파일이 directory가 있으면 extensionFilter를 재귀로 돌리고 결과값을 liblist에 넣어준다.
  • directory가 아닐 때, 그 파일의 확장자가 csv이면 liblist에 넣어준다.
  • 이 과정을 반복해서 끝내면, liblist를 반환해준다.



소스코드

private ArrayList extensionFilter(File folder){

        ArrayList liblist = new ArrayList<>();
        File[] files = folder.listFiles();

        if(files != null){
            for(File file : files){
                if(file.isDirectory()) liblist.addAll(extensionFilter(file));
                else{
                    if(file.getName().endsWith(".csv")) liblist.add(file.toString());
                }
            }
        }

        return liblist;
    }




2. 파싱하기

csv파일을 찾았으면 이제 파싱을 해야한다. 파싱은 CSVParsing 클래스에 구현하였다.



방법

  • filename이란 전역변수를 설정하고 setter로 MainActivity에서 값을 받아온다.
  • book이란 전역 Arraylist를 생성한다. (책 목록을 담기위한 리스트)
  • ErrorCheck 전역변수를 생성한다. (올바른 형식의 csv파일인지 체크)
  • Parser 메소드가 실행될 때  book의 데이터를 전부 삭제하고 Errorcheck를 0으로 설정해준다. (만약 선택하는 csv파일이 여러개이고 book을 지워주지 않으면 데이터가 쌓여서 복수의 csv파일의 데이터가 전부 누적되기 때문에 새로운 csv파일을 선택할 때마다 데이터를 지워준다. ErrorCheck도 같은 이유.)
  • 파일을 열어 한줄씩 읽으면서 5개로 나눠준다. 이 때 [비고] 부분은 빈칸이 많으므로 limit를 5로 설정해준다.
  • 목록이 5개가 아니면 ErrorCheck = 1로 만들어준다.
  • 맨 앞의 string이 "번" (번호 - 이름 -... 으로 시작하는 목차 부분은 당연히 책 리스트에 넣어주면 안됨.) 이면 리스트에 넣지 않고, 그 밖에는 book에 넣어준다. 만약 탐색 도중에 ErrorCheck = 1인 경우가 발생한다면 목록이 형식에 맞지 않는 경우이므로 탐색을 중지한다.



소스코드

package com.example.bethanylibrary;

import android.support.v7.app.AppCompatActivity;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class CSVParsing extends AppCompatActivity {

    public static ArrayList book = new ArrayList();
    public static String filename = new String();
    public static int ErrorCheck = 0;


    public void Parser(){

        ErrorCheck = 0;
        book.clear();

        try{
            File file = new File(filename);
            BufferedReader br = new BufferedReader(new FileReader(file));

            String line = "";

            while((line = br.readLine()) != null){

                String[] token = line.split(",", 5);

                if(token.length != 5) { ErrorCheck = 1; break; }

                if(!token[0].contains("번")) {
                    if (ErrorCheck == 1) break;
                    book.add(token);
                }
            }
            br.close();
        }
        catch(FileNotFoundException e){

        }
        catch(IOException e){

        }
    }

    public ArrayList getBook(){
        return book;
    }

//    public String getFilename() {
//        return filename;
//    }

    public void setFilename(String filename) {
        this.filename = filename;
    }
}




3. 파싱 체크 및 화면 전환

파싱을 구현했으면 이제 제대로 파싱이 이루어져서 화면 전환을 해줄 수 있는지 체크를 해줘야한다. 이 때 파일을 찾는 과정은 "찾기"버튼을 통해 이루어지며 파싱하는 과정은 찾은 파일들의 리스트에서 선택한 리스를 터치했을 때 이루어진다.. 따라서 FindClick 메소드와 그 안의 listview.setOnItemClickListener 에 의해서 이루어지게 된다.


방법

  • 파일 탐색을 끝내고 반환된 리스트를 가져올 Interfiles, 리스트뷰, 리스트뷰와 Interfiles를 연결할 adapter를 생성한다.
  • 원하는 파일을 선택하면 그 파일의 이름을 CSVParsing의 filename으로 set해주고 Parser 메소드를 실행한다. 
  • CSVParsing의 ErrorCheck = 1이면 에러메세지를 출력한다.
  • 그렇지 않으면 파싱을 끝낸 후 화면을 전환해준다.



소스코드

public void FindClick(View v){


        ArrayList Interfiles = extensionFilter(Environment.getExternalStorageDirectory());

        ListView listview = (ListView)findViewById(R.id.lib_list);

        final ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, Interfiles);
        listview.setAdapter(adapter);


        listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {

                String Selectfile = (String) parent.getItemAtPosition(position);
                CSVParsing fileparser = new CSVParsing();
                fileparser.setFilename(Selectfile);

                fileparser.Parser();

                if(fileparser.ErrorCheck != 1) {
                    Intent intent = new Intent(MainActivity.this, LibraryView.class);
                    startActivity(intent);
                }
                else{
                    Toast.makeText(MainActivity.this, "올바른 형식의 목록이 아닙니다.\n[책번호 - 책이름 - 책위치 - 날짜 - 비고]", Toast.LENGTH_LONG).show();
                    //Toast.makeText(MainActivity.this, "" + fileparser.getCheck(), Toast.LENGTH_LONG).show();
                }
            }
        });

    }

댓글