티스토리 뷰

728x90
반응형

IO란?


  • input과 output의 약자로 입력과 출력을 나타냅니다. 즉 컴퓨터 내부 또는 외부와의 장치와 프로그램간의 데이터를 주고 받는것을 말합니다.

 

스트림이란?


  • 스트림이란 실제의 입력이나 출력이 표현된 테이터의 흐름을 말하며, 자바에서는 파일이나 콘솔에서의 입출력을 스트림을 통해 다룹니다. 스트림은 한 방향으로만 통신이 가능하기 때문에 입력과 출력을 동시에 처리할 수 없고 출력과 입력을 동시에 할려면 입력스트림과 출력스트림 각각을 만들어야 합니다.
  • 스트림이란 자바8부터 추가된 컬렉션(배열 포함)의 저장 요소를 하나씩 참조해서 람다식으로 처리할 수 있도록 해주는 반복자 입니다.

 

스트림의 특징


  • Stream은 Iterator와 비슷한 역할을 하는 반복자이지만, 람다식으로 요소 처리 코드를 제공하는 점과 내부 반복자를 사용하므로 병렬처리가 쉽다는 점 그리고 중간 처리와 최종 처리 작업을 수행하는 점에서 많은 차이점을 가지고 있습니다.

 

스트림의 종류


  • BaseStream 인터페이스에는 모든 스트림에서 사용할 수 있는 공통 메서드들이 정의되어 있을뿐 코드에서 직접적으로 사용되지는 않습니다. 하위 스트림인 Stream, IntStream, LongStream, DoubleStream이 직접적으로 이용되는 스트림입니다. Stream은 객체 요소를 처리하는 스트림이고 IntStream, LongStream, DoubleStream은 각각 기본 타입인 int, long, double 요소를 처리하는 스트림입니다.

배열로부터 스트림 사용
public class Example {
    public static void main(String[] args) {
        String[] strArray = {"홍길동", "이순신", "주몽"};
        int[] intArray = {1, 3, 5, 7 ,9, 10};
        double[] doubleArray = {10.0, 20.0, 30.1, 40.5};

        Stream<String> stringStream = Arrays.stream(strArray);
        stringStream.forEach(item -> {
            System.out.println(item);
        });

        IntStream intStream = Arrays.stream(intArray);
        intStream.forEach(item -> {
            System.out.println(item);
        });

        DoubleStream doubleStream = Arrays.stream(doubleArray);
        doubleStream.forEach(item -> {
            System.out.println(item);
        });

        double avg = Arrays.stream(doubleArray).average().getAsDouble();
        System.out.println(avg);
    }
}

 

숫자범위로부터 스트림 사용
public class Example {
    static int sum;

    public static void main(String[] args) {
        IntStream intStream = IntStream.rangeClosed(1, 100);
        intStream.forEach(item -> {
            sum += item;
        });

        System.out.println(sum); // 5050
    }
}

 

파일로부터 스트림 사용
public class Example {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("C:\\Users\\cova7\\Desktop\\테스트.txt");
        Stream<String> stream = Files.lines(path, Charset.defaultCharset());

        stream.forEach(item -> {
            System.out.println(item);
        });
    }
}

 

스트림 사용 예제


  • Iterator를 사용한 것보다 Stream을 사용하게 되면 훨씬 더 깔끔한 코드를 작성할 수 있습니다.
Iterator를 사용하여 반복
public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class Example {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("홍길동", 10),
                new Student("이순신", 20),
                new Student("유관순", 30),
                new Student("주몽", 40)
        );

        Iterator<Student> iterator = students.iterator();

        while (iterator.hasNext()) {
            Student item = iterator.next();
            System.out.println(item.getName() + " - " + item.getAge());
        }
    }
}

 

Stream을 사용하여 반복
public class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class Example {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("홍길동", 10),
                new Student("이순신", 20),
                new Student("유관순", 30),
                new Student("주몽", 40)
        );

        Stream<Student> stream = students.stream();
        stream.forEach(student -> {
            System.out.println(student.getName() + " - " + student.getAge());
        });

        double avg = students.stream().mapToInt(Student :: getAge).average().getAsDouble();
        System.out.println(avg);
    }

 

 

버퍼란?


  • 버퍼란 데이터를 전송하는 상호간의 장치에서 고속의 장치와 저속의 장치 간의 속도 차이로 인해 저속의 장치가 작업을 이행하는 동안 고속의 장치가 기다려야하는 현상을 줄어주는 기술이며 데이터를 임시 저장하는 공간을 의미합니다.
  • 이렇게 버퍼를 사용하게 되면 운영체제의 API 호출 횟수를 줄여서 입출력 성능을 개선할 수 있습니다.

 

버퍼 사용 예제


  • 해당 예제는 문자열에 입력하여 파일에 작성하는 예제입니다.
public class Example {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\cova7\\Desktop\\테스트.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter writer = new BufferedWriter(new FileWriter(file, true));

        writer.write("\n" + reader.readLine());
        writer.write("\n" + reader.readLine());
        writer.flush();
        writer.close();

        Path path = Paths.get("C:\\Users\\cova7\\Desktop\\테스트.txt");
        Stream<String> stream = Files.lines(path, Charset.defaultCharset());

        stream.forEach(text -> {
            System.out.println(text);
        });
    }
}

 

채널이란?


  • IO에서 바이트 스트림과 문자 스트림으로 데이터를 읽은 것과는 다르게 NIO에서는 채널을 통해 데이터를 읽고 씁니다.

 

채널과 스트림의 차이


  • 채널은 읽고 쓰는것이 모두 가능한 양방향성을 가지고 스트림은 읽는 것이나 쓰는것 중 하나만 가능한 단방향성을 가집니다.
  • 채널은 비동기적으로 읽고 쓸 수 있습니다.
  • 채널은 항상 버퍼로 부터 읽거나 버퍼로 작성합니다.

 

채널의 특징


  • Socket과 연결되어 입출력 역할을 수행합니다.
  • 입출력을 동시에 할 수 있습니다.(양방향성)
  • Selector와 연결되어 있고, 하나의 Selector에는 다수의 채널이 존재할 수 있습니다.
  • Blocking이 된 스레드를 깨우거나 다시 Blocking할 수 있습니다.

 

 

InputStream과 OutputStream


InputStream
  • InputStream은 바이트 기반 스트림의 최상위 클래스로 추상 클래스입니다. 모든 바이트 기반 스트림은 InputStream을 상속받아서 만들어 집니다.

 

주요 메서드


read()
  • read() 메서드는 입력 스트림으로부터 1바이트를 읽고 4바이트를 int 타입으로 리턴합니다. 만약 더 이상 입력 스트림으로부터 바이트를 읽을 수 없다면 read() 메서드는 -1을 리턴하는데 이것을 이용하면 읽을 수 있는 마지막 바이트까지 반복문을 돌며 한 바이트씩 읽을 수 있습니다.
public class Example {
    public static void main(String[] args) throws IOException {
        FileInputStream  fileInputStream = new FileInputStream("C:\\Users\\cova7\\Desktop\\테스트.txt");

        int i = 0;
        while ((i = fileInputStream.read()) != -1) {
            System.out.write(i);
        }
        fileInputStream.close();
    }
}

close()
  • close() 메서드는 InputStream을 더이상 사용하지 않을 경우에 close() 메서드를 호출하여 InputStream에서 사용했던 자원을 풀어줍니다.

OutputStream
  • OutputStream은 바이트 기반 출력 스트림의 최상위 클래스로 추상 클래스입니다. 모든 바이트 기반 스트림은 OutputStream을 상속받아서 만들어집니다.

 

주요 메서드


write()
  • write() 메서드는 매개변수로 주어진 int값에서 끝에 있는 1바이트만 출력 스트림으로 보냅니다.
public class Example {
    public static void main(String[] args) throws IOException {
        File file = new File("C:\\Users\\cova7\\Desktop\\테스트.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file, true);

        int data = 0;
        while ((data = System.in.read()) != -1) {
            fileOutputStream.write(data);
        }

        fileOutputStream.flush();
        fileOutputStream.close();
    }
}

 

flush()와 close()
  • flush() 메서드는 버퍼에 잔류하고 있는 데이터를 모두 출력시키고 버퍼를 비우는 역할을 수행합니다. 만약에 프로그램에서 더이상 출력할 버퍼가 없다면 flush() 메서드를 마지막으로 호출하여 버퍼에 잔류하는 모든 데이터를 출력해야 합니다. 또한 OutputStream을 더이상 사용하지 않는다면 close() 메서드를 호출하여 자원을 풀어줍니다.

 

Byte와 Character 스트림


 

Byte Stream
  • 바이트 단위로 데이터를 전송합니다.
  • 자바의 스트림은 기본적으로 byte 단위로 스트림을 전송하며 입출력 대상에 따라 제공하는 클래스가 다릅니다. 또한 그림, 멀티 미디어, 문자 등 모든 종류의 데이터를 주고 받을 수 있다는 특징을 가지고 있습니다.

 

Byte 스트림 클래스의 종류


FileInputStream / FileOutputStream
  • 파일 입출력 대상
ByteArrayInputStream / ByteArrayOutputStream
  • 메모리 입출력 대상
PipedInputStream / PipedOutputStream
  • 프로세스 입출력 대상
AudioInputStream / AudioOutputStream
  • 오디오 장치 입출력 대상

Charactor Stream
  • 자바에서 가장 작은 타입인 char 형이 2바이트 이므로 1바이트씩 전송되는 바이트 기반입니다.
  • 스트림으로 원할한 처리가 힘든 경우가 있습니다. 이러한 경우를 해결하기 위해 자바는 문자 기반 스트림을 지원합니다. 문자 기반 스트림은 오직 문자 데이터를 주고 받기 위해 존재하는 스트림으로 문자 데이터를 입출력할 때 사용하는 스트림입니다. Reader와 Writer 클래스를 상속받아서 사용합니다.

 

Charactor 스트림 클래스의 종류


FileReader / FileWriter
  • 파일 입출력 대상
CharArrayReader / CharArrayWriter
  • 메모리 입출력 대상
PipedReader / PipedWriter
  • 프로세스 입출력 대상
StringReader / StringWriter
  • 문자열 입출력 대상

 

표준 스트림


  • 자바에서는 콘솔과 같은 표준 입출력 장치를 위해 System이라는 표준 입출력 클래스를 제공하고 있습니다.
  • System 클래스는 java.lang 패키지에 포함되어 있습니다.
  • 표준 입출력 스트림은 자바에서 기본적으로 생성하기 때문에 별도로 생성할 필요가 없습니다.
System.in
  • 콘솔로부터 데이터를 입력 받음
System.out
  • 콘솔에 데이터를 출력함
System.err
  • 콘솔에 에러 데이터를 출력함

 

 

728x90
반응형

'JAVA > JAVA기본' 카테고리의 다른 글

JAVA - 람다식이란?  (0) 2022.02.10
JAVA - 제네릭이란?  (0) 2022.01.30
JAVA - 어노테이션이란?  (0) 2022.01.29
JAVA - Enum이란?  (0) 2022.01.29
JAVA - Main Thread란(feat.동기화, 데드락)?  (0) 2022.01.27