본문 바로가기

issue & tip

파일 입출력

반응형

파일


텍스트를 읽는 방법

- 파일의 문자를 한문자씩 읽는 방법(FileReader 클래스)

- 텍스트를 한줄 씩 읽는 방법(BufferedReader 클래스)

- 텍스트를 한번에 모두 읽는 방법(Scanner 클래스, Files 클래스)


 파일의 문자를 한문자씩 읽는 방법(FileReader 클래스)

FileReader 클래스는 텍스트 파일에서 문자 단위로 데이터를 읽어 들이는 클래스


FileReader(File file) - File객체를 지정해서 FileReader를 생성

FIleReader(String fileName) - 읽어드릴 파일명을 지정해서 FileReader를 생성


int read() - 입력스트림에서 한 개의 문자를 읽어 반환

void close() - 입력 스트림을 닫고, 스트림에 관련된 모든 시스템 리소스를 해제



package com.example.demo.file;


import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;


public class ReadText {


public static void main(String[] args)  {

try {

File file = new File("C:\\alice.txt");

FileReader fileReader = new FileReader(file);

int singlenCh = 0;

while ((singlenCh = fileReader.read()) != -1) {

System.out.println((char)singlenCh);

}

fileReader.close();

} catch (FileNotFoundException e) {

System.out.println(e);

} catch (IOException e){

System.out.println(e);

}

}

}



텍스트를 한줄 씩 읽는 방법(BufferedReader 클래스)

한줄 단위로 텍스트를 읽어들이는 BufferedReader 클래스 사용


BufferedReader(Reader in) - 기본 크기의 버퍼로 버퍼링된 문자열 입력 스트림 생성

BUfferedReader(Reader in, int sz) - 지정한 크기의 버퍼로 버퍼링된 문자열 입력 스트림 생성


String readLine() - 텍스트를 한줄씩 읽어드린다. 단 행의 마지막 문자(개행 문자)는 포함하지 않는다. 스트림의 끝에 도달하면 null을 반환

Stream<String> lines() - 텍스트를 한줄씩 읽어드린다. 파일의 마지막 행인지 체크했던 null 체크가 필요없다 (자바 8에 추가된 메서드)


package com.example.demo.file;


import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;


public class BufferedReaderText {


public static void main(String[] args)  {

try {

File file = new File("C:\\alice.txt");

FileReader fileReader = new FileReader(file);

BufferedReader bufferedReader = new BufferedReader(fileReader);

String line = "";

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

System.out.println(line);

}

bufferedReader.close();

} catch (FileNotFoundException e) {

System.out.println(e);

} catch (IOException e){

System.out.println(e);

}

}

}



package com.example.demo.file;


import java.io.BufferedReader;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileReader;

import java.io.IOException;


public class BufferedReaderText2 {


public static void main(String[] args)  {


File file = new File("C:\\alice.txt");

// try-with-resources try블록 빠져온 시점에 자동으로 close된다.

try (FileReader fileReader = new FileReader(file);

BufferedReader bufferedReader = new BufferedReader(fileReader)) {

String line = "";

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

System.out.println(line);

}

} catch (FileNotFoundException e) {

System.out.println(e);

} catch (IOException e){

System.out.println(e);

}

}

}


텍스트를 한번에 모두 읽는 방법(Scanner 클래스, Files 클래스)


Scanner(File source) - 지정된 파일에서 입력받을 Scanner를 생성

boolean hasNextLine() - 다음행이 있을 때는 true 반환

boolean useDelimiter(String pattern) - 스캐너에서 이용할 구분 문자를 지정된 패턴으로 설정

String next() - 스캐너에서 다음 토큰을 가져옴

String nextLine() - 스캐너에서 다음 행을 가져옴


package com.example.demo.file;


import java.io.File;

import java.io.FileNotFoundException;

import java.util.Scanner;


public class ScannerText {


public static void main(String[] args)  {


try {

File file = new File("C:\\alice.txt");

Scanner scanner = new Scanner(file);

System.out.println(scanner.useDelimiter("\\z").next());

scanner.close();

} catch (FileNotFoundException e) {

System.out.println(e);

}

}

}



텍스트를 한번에 모두 읽는 방법(Files 클래스)

Files 클래스는 자바7부터 도입


static 메서드만 구성되어 있으므로 생성자는 없다


boolean isReadable(Path path) - 파일을 읽을 수 있는지 판정

byte[] readAllBytes(Path path) - 파일의 모든 바이트를 읽고, 바이트 배열로 반환(파일 2GB을 넘을경우 OutOfMemoryError 예외를 던짐)

List<String> readAllLines(Path path, Charset cs) - 지정한 문자셋으로 파일의 모든 행을 String으로 가져온다. 자바8부터는 문자셋을 생략할 수 있다.(생략시 기본값 UTF-8)

Stream<String> lines(Path path, Charset cs) - 지정한 문자셋으로 파일의 모든 행을 Stream으로 가져온다. 자바8부터는 문자셋을 생략할 수 있다.(생략시 기본값 UTF-8)


Files 클래스에서 대상이 되는 파일과 폴더는  Path와 Paths 클래스로 지정할 수 있다.


Path get(String first, String... more) - 지정한 경로 문자열을 연결해 파일 경로를 반환 get("C:\\", "temp", "aaa") 일때 반환값은 C:\\temp\aaa다



package com.example.demo.file;


import java.io.IOException;

import java.nio.charset.Charset;

import java.nio.charset.StandardCharsets;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;

import java.util.ArrayList;

import java.util.List;


public class FilesText {


public static void main(String[] args)  {


Path path = Paths.get("C:\\alice.txt");

Charset cs = StandardCharsets.UTF_8;

List<String> list = new ArrayList<String>();

try {

list = Files.readAllLines(path, cs);

} catch (IOException e) {

e.printStackTrace();

}

for(String readLine : list) {

System.out.println(readLine);

}

}

}



파일쓰기


- FileWriter 클래스로 파일에 쓰기

- BufferedWriter 클래스로 파일에 쓰기

-  Files 클래스로 파일에 쓰기


FileWriter 클래스로 파일에 쓰기


FileWriter(File file) - File 오브젝트로 FileWriter 오브젝트를 생성

FileWriter(File file, boolean append) - File 오브젝트로 FileWriter 오브젝트를 생성(두번째 인수가 true인경우 파일에 추가로 기록하고 false 인경우에는 처음부터 기록)


FileWriter(String fileName) -  지정한 팡리명으로 FileWriter 오브젝트를 생성

FileWriter(String fileName, boolean append) - 지정한 파일명으로 FileWriter 오브젝트를 생성(두번째 인수가 true인경우 파일에 추가로 기록하고 false인경우 처음부터 기록)



int write(String srt) - 지정한 문자열을 출력

void close() - 입력 스트림을 닫고, 스트림과 관련된 모든 시스템 리소스를 해제


package com.example.demo.file;


import java.io.File;

import java.io.FileWriter;


public class FileWriterText {

public static void main(String[] args) {

try {

File file  = new File("C:\\sampleWriter.txt");

FileWriter fileWriter = new FileWriter(file);

fileWriter.write("출력 문자열 1\r\n");

fileWriter.write("출력 문자열 2\r\n");

fileWriter.close();

} catch (Exception e) {

System.out.println(e);

}

}

}



BufferedWriter 클래스로 파일에 쓰기

출력할 문자열을 버퍼링한 후에 파일에 쓰면 문자를 효율적으로 출력할 수 있고 실행시 CPU의 부하도 줄일 수 있다.


BufferedWriter(Writer out) - 기본크기의 출력 버퍼를 확보한후 출력 스트림을 생성

BufferedWriter(Writer out, int sz) - 지정한 크기로 출력 버퍼를 확보한 후 출력 스트림을 생성


void write(String str) - 지정한 문자열을 기록

void newLine() - 개행문자를 기록

void close() - 출력 스트림을 닫고, 스트림과 관련된 모든 시스템 리소스를 해제


package com.example.demo.file;


import java.io.BufferedWriter;

import java.io.File;

import java.io.FileWriter;


public class BufferdWriterText {

public static void main(String[] args) {

try {

File file  = new File("C:\\sampleBufferedWriter.txt");

//래핑

BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file));

if(file.isFile() && file.canWrite()) {

bufferedWriter.write("문자열 추가 1");

bufferedWriter.newLine();

bufferedWriter.write("문자열 추가 2");

bufferedWriter.newLine();

bufferedWriter.close();

}

} catch (Exception e) {

System.out.println(e);

}

}

}




Files 클래스로 파일에 쓰기


boolean isWritable(Path path) - 파일에 쓸수 있는지 판정

BufferedWriter newBufferedWriter(Path path, Charset cs, OpenOpton... option) - 텍스트를 기록할 BufferedWriter를 생성

Path write(Path path, Iterable<? extends CharSequnece> lines, Charset cs, OpenOption...) - 텍스트를 파일에 기록


package com.example.demo.file;


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.IOException;

import java.nio.charset.StandardCharsets;

import java.nio.file.Files;

import java.nio.file.Path;

import java.nio.file.Paths;


public class FilesWriterText {

public static void main(String[] args) throws IOException {

//읽기용 파일

Path input = Paths.get("C:\\sampleBufferedWriter.txt");

//쓰기용 파일

Path output =Paths.get("C:\\sampleFilesWriter.txt");

//일기용 파일의 내용을 BufferedReader 오브젝트로 가져온다

try(BufferedReader reader = Files.newBufferedReader(input, StandardCharsets.UTF_8);

BufferedWriter writer = Files.newBufferedWriter(output, StandardCharsets.UTF_8) ){

//읽기용 파일의 내용을 한 줄 씩 읽고,

//빈 줄이 없는 경우 쓰기용 파일에 기록한다.

for (String line = reader.readLine(); line != null; line= reader.readLine() ) {

System.out.println(line);

//파일에 쓰기

writer.write(line);

writer.newLine();

}

}

}

}



CSV 파일의 입출력


CSV(Comma Separated Values) 파일의 입출력

데이터의 각 요소를 콤마로 구분하고 개행 문자가 그대로 데이터 행의 구분을 나타낸다.

.csv확장자가 붙은 파일로 저장한다.


BufferedReader 클래스를 이용


package com.example.demo.file;


import java.io.BufferedReader;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.nio.charset.Charset;

import java.nio.file.Files;

import java.nio.file.Paths;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;



public class ReadCsv {


public static void main(String[] args) {

// 반환용 리스트 변수

List<List<String>> ret = new ArrayList<List<String>>();

//입력 스트림 오브젝트 생성

BufferedReader br = null;

try {

// 대상 csv 파일의 경로 설정

br = Files.newBufferedReader(Paths.get("C:\\ReadCsvFile.csv"));

Charset.forName("UTF-8");

//csv 파일에서 읽어 드린 1행분의 데이터

String line = "";

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

//csv 파일의 1행을 저장하는 리스트 변수

List<String> tempList = new ArrayList<>();

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

//배열에서 리스트로 변환

tempList = Arrays.asList(array);

//리스트 내용 출력

System.out.println(tempList);

//반환용 리스트에 1행의 데이터를 저장

ret.add(tempList);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

try {

if(br != null) {

br.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}


}


}


결과

[사원번호,  이름영문,  이름한글,  성별,  입사연월일,  소속부서,  사원구분]

[1,  Hong GILDONG,  홍길동,  1,  20150401,  인사부,  1]

[2,  SIM AYUN,  심아윤,  2,  20100401,  개발부,  2]

[3,  LEE CHULSHOO,  이철수,  1,  20150401,  경리부,  1]



데이터가 List<List<String>> 형식으로 저장됨


File이나 FileReader 클래스를 랩해서 파일을 읽어드리이는 부분까지 텍스트를 읽는 과정은 같다.

중요한 것은 행 단위로 읽어 들인 데이터에서 콤마를 검출해 List 오브젝트에 저장하는 방법이다


콤마 검출방법

정해진 구분 문자를 검출하고자 할때 자바 1.4이전에는 StringTokenizer 클래스를 사용했다.

현재는 권장하지 않고 String 클래스의 split 메서드를 이용해 콤마로 구분된 문자열에서 데이터를 뽑아낸다

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


split 메서드의 인수에는 구분 문자를 지정한다.

정규표현식을 지정할수도 있다.

split 메서드의 반환값은 구분 문자로 나눈 문자열 배열이므로, 이후에 이 배열을 차례로 List 오브젝트에 저정하면 2차원 배열 List<List<String>>이 완성된다.


CSV 파일쓰기


package com.example.demo.file;


import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.nio.charset.Charset;

import java.nio.file.Files;

import java.nio.file.Paths;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;



public class WriteCsv {


public static void main(String[] args) {

//출력 스트림 오브젝트 생성

BufferedWriter writer = null;

try {

writer = Files.newBufferedWriter(Paths.get("C:\\WriteCsvFile.csv"), Charset.forName("UTF-8"));

//csv 파일 읽기

List<List<String>> allData = readCSV();

for(List<String> newLine : allData) {

//1행분의 데이터

List<String> list = newLine;

for(String data : list) {

writer.write(data);

writer.write(",");

}

//추가할 주소 데이터추가

writer.write("주소");

//개행 코드 추가

writer.newLine();

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

try {

if(writer != null) {

writer.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}

}


private static List<List<String>> readCSV() {

// 반환용 리스트 변수

List<List<String>> ret = new ArrayList<List<String>>();

//입력 스트림 오브젝트 생성

BufferedReader br = null;

try {

// 대상 csv 파일의 경로 설정

br = Files.newBufferedReader(Paths.get("C:\\ReadCsvFile.csv"));

Charset.forName("UTF-8");

//csv 파일에서 읽어 드린 1행분의 데이터

String line = "";

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

//csv 파일의 1행을 저장하는 리스트 변수

List<String> tempList = new ArrayList<>();

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

//배열에서 리스트로 변환

tempList = Arrays.asList(array);

//리스트 내용 출력

System.out.println(tempList);

//반환용 리스트에 1행의 데이터를 저장

ret.add(tempList);

}

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}finally {

try {

if(br != null) {

br.close();

}

} catch (Exception e) {

e.printStackTrace();

}

}

return ret;

}


}



XML 입출력

XML(eXtensible Markup Language)은 인터넷 상에서 다양한 데이터를 다룰때 사용하는 마크업 언어의 일종이다.

웹상에서 데이터를 교환할 때 이용한다.


XML이란

W3C라는 표준화 단체가 고안했다.

XML은 HTML처럼 SGML에 파생되었다.

첫번째 사양은 XML 1.0으로서 1998년에 권고됐고, 2000년에 XML 1.0 2판이 권고됐다.

텍스트 기술 방법을 규정한 사양이고 XML사양을 따라 기술된 문서가 XML문서이다.


기본포맷이 텍스트 파일

유니코드를 지원


XML의 구조

XML 트리구조는 최상위에 유일한 루트 요소가 있고, 그 아래에 요소가 매달린 구조이다.

부모 또는 부모노드, 아래 있는 요소는 자식 또는 자식노드로 부른다.


예)

<?xml version="1.0" encoding="UTF-8"?>

<food>

<item>

<type>vegetable</type>

<name>양파</name>

<locality>무안</locality>

<productname>황토 양파</productname>

</item>

<item>

<type>fruit</type>

<name>딸기</name>

<locality>논산</locality>

<productname>유기농 딸기</productname>

</item>

</food>



XML 선언

<?xml version="1.0" encoding="UTF-8" standalone="yes|no"?>


version - XML사양의 버전 기본으로 1.0

encoding - 문자인코딩 지정 기본 UTF-8, UTF-16

stanalone - DTD  파일을 사용할지  yes면 DTD파일을 사용하지 않는다. no면 DTD파일을 사용한다.

생략하면 no로 간주한다.



XML 파일 읽기


- DOM (Document Object Model)

WWW의 사실상 표준화 단체인 W3C에서 정식으로 권고한 사양이다.

프로그래밍 언어에 의존하지 않는 API이며, XML 문서에 대응하는 트리 구조를 정적으로 메모리상에 유지하므로 트리에 존재하는 임의 요소에 랜덤하게 액세스할 수 있다.


- SAX(Simple API for XML)

메일링 리스트 XML-DEV의 협업으로 탄생해 국제적인 표준화  단체에서 규정한 사양은 아니지만 사실상의 표준 API이다.

이벤트를 기반으로 순차적으로 XML문서를 처리하고 메모리 소비량과 실행 속도 면에서 뛰어난 경량 API이다

다만, 랜덤 액세스와 구조 변경에 약한것이 단점이다.


- JAXP

자바 표준 패키지에 포함되어 DOM/SAX API를 추상화하여, 자바 애플리케이션에 XML 프로세서 구현에 의존하지 않는 보편적인 API를 제공. JAXP를 따르면 XML 프로세서 구현에 의존하지 않는 범용적인 코드를 기술할 수 있게 된다.


DOM의 기본

XML을 트리구조 데이터 집합으로 처리한다.

DOM에서는 처음 XML문서를 모두 메모리에 읽어드린다.

읽어드린 요소와 텍스트, 속성 등의 데이터는 계층적으로 배치된다.

그런다음 루트 요소부터 자식 요소를 향해 차례대로 액세스한다.


DOM에서 이용하는 클래스

XML문서에 DOM Document 인스턴스를 가져오는 DocumentBuilder 클래스


Document parse(InputStream is) - 지정한 InputSteam에서 XML문서를 읽고 Document오브젝틀 반환

Document parse(InputStream is, String systemId) - 지정한 InputStream에서 XML 문서를 읽고 Document 오브젝트를 반환(두번째 인수에는 상대 URI를 해석할 기본 URL을 지정)

Document parse(String uri) - 지정한 URI를 읽고  Document 오브젝트를 반환

Document parse(File file) - 지정한 파일을 읽고 Document 오브젝트를 반환

Document parse(InputSource is) - 지정한 InputSource에서 XML문서를 읽고 Document 오브젝트를 반환


DocumentBuilder 오브젝트는 DocumentBuilderFactory 클래스의 newInstance 메서드로 생성

DocumentBuilder사용법

File file = new File("C:\\sample.xml");

//DOM 서버용 팩토리 생성

DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();

DocumentBuilder docBuilder = null;


docBuilder = docFactory.newDocumentBuilder();

Document doc = docBuilder.parse(file);


Node를 이용해 요소와 속성정보를 가져온다.

XML 등 정해진 문법에 따라 기술된 문장을 해석하는 처리를 파싱이라고 하고, 파싱하는 프로그램을 파서라고 한다.

Node는 파싱할때 사용하는 인터페이스이다.


노드란 태그를 나타내는 엘리먼트(요소)와 문을 나타내는 텍스트의 총칭이다.

DOM에서는 문서 내의 요소와 텍스트를 노드(가지)로 간주해서 다룬다.

XML은 트리구조로 되어있다.(노드 트리)

노드 트리의 각 노드는 계층관계로 되어있다.

계층 관계에 있는 노드를 부모노드와 자식노드라고 부른다.

또한 같은 레벨의 노드는 형제 노드


최상위 노드를 루트

루트 외의 노드에서 반드시 하나의 부모 노드가 있다.

<item> 요소가 부모노드고 <type>,<name>,<locality>,<productname>이 자식 노드이다.


Node클래스의 주요 메서드


Node getFirstChild() -  부모 노드 바로 아래 첫 자식 노드를 반환

Node getLastChild() - 부모 노드 바로 아래 마지막 자식 노드를 반환

Node getNextSibling() - 다음 형제 노드를 반환

String getNodName() - 노드의 이름을 반환

String getNodeType() -  노드의 종류를 반환

String getNodeValue() - 노드의 값을 반환

NodeList getChildNodes() - 자식 노드의 목록 반환


자식 노드가 하나뿐인 경우에는 getFirstChild 메서드로 자식 노드를 가져올 수 있다.

여러개인 경우에는 getNextSibling 메서드로 차례대로 형제 노드를 더듬어가야한다.

이때 편리한 것이 getChildNodes 메서드로 자식 노드를 모아서 NodeList 오브젝트로 가져올수 있다.


NodeList 클래스의 주요 메서드

int getLength() - 리스트내 노드 수를 반환

Node item(int index) -  리스트내 index번째 노드를 반환


XML 파일의 읽기 처리는 이상의 클래스를 조합해서 작성한다.


package com.eeswk.xml;


import java.io.File;

import java.io.IOException;


import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;


import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

import org.xml.sax.SAXException;


public class ReadXml {

public static void main(String[] args) {

File file = new File("C:\\sample.xml");

//DOM 서버용 팩토리 생성

DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();

DocumentBuilder docBuilder = null;

try {

docBuilder = docFactory.newDocumentBuilder();

Document doc = docBuilder.parse(file);

Element root = doc.getDocumentElement();

System.out.println("노드명: " + root.getNodeName());

//루트 요소의 자식 노드를 가져온다

NodeList rootChildren = root.getChildNodes();

System.out.println("자식 요소 수: " + rootChildren.getLength());

System.out.println("-----------------------------");

for (int i = 0; i < rootChildren.getLength(); i++) {

//자식 노드를 추출

Node child = rootChildren.item(i);

//노드일경우

if(child.getNodeType() == Node.ELEMENT_NODE) {

NodeList personChildren = child.getChildNodes();

for(int j=0; j < personChildren.getLength(); j++) {

//뽑아낸 자식 노드에서 차례로 항목을 추출

Node personNode  = personChildren.item(j);

//노드명

String text = personChildren.item(j).getNodeName();

if(personNode.getNodeType() == Node.ELEMENT_NODE) {

//노드값

String value = personChildren.item(j).getTextContent().trim();

if(text.equals("type")) {

System.out.println("종류: " + value);

}else if(text.equals("name")) {

System.out.println("이름: "+ value);

}else if(text.equals("locality")) {

System.out.println("원산지: " +value);

}else if(text.equals("productname")) {

System.out.println("제품명: " + value);

}

}

}

System.out.println("-----------------------------");

}

}

} catch (ParserConfigurationException e) {

e.printStackTrace();

} catch (SAXException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}


}


출처-실무에서 바로 통하는 자바

반응형

'issue & tip' 카테고리의 다른 글

결합도  (0) 2018.05.17
응집도  (0) 2018.05.09
래퍼클래스와 제네릭  (0) 2018.04.24
부동소수점  (0) 2018.04.24
스레드  (0) 2018.04.24