유닉스 시스템에서 왜 파일을`read ()`또는`write ()`할 수 있도록 명시 적으로`open ()`및`close ()`파일을 사용해야합니까?


50

open()close()유닉스 파일 시스템 디자인에 존재 하는가?

OS가 처음 감지 read()하거나 write()호출되어 open()정상적으로 수행되는 작업을 수행 할 수 없었 습니까?


22
이 모델은 파일 시스템의 일부가 아니라 Unix API 가 아니라는 점에 주목할 가치가 있습니다. 파일 시스템은 디스크에서 바이트가 어디로 가고 파일 이름을 넣을 위치와 관련이 있습니다. UFS 또는 ext4와 같은 Unix 파일 시스템 위에 설명하는 대체 모델을 사용하는 것이 가능할 것입니다. 커널을 호출하여 파일 시스템에 대한 적절한 업데이트로 변환합니다 (현재와 동일).
marcelm

18
말했듯이, 이것이 왜 open()존재 하는지에 관한 것입니다. "OS가 read () 또는 write ()를 처음 감지하고 open ()이 일반적으로하는 모든 작업을 수행 할 수 없었습니까?" 마감 이 일어날 때 이에 대한 제안 이 있습니까?
Joshua Taylor

7
액세스 할 파일 read()또는 write()파일을 어떻게 말 하시겠습니까? 아마도 경로를 통과함으로써. 파일 경로에 액세스하는 동안 파일 경로가 변경되면 (2 read()또는 write()통화 사이 ) 어떻게됩니까?
user253751

2
또한 보통의 액세스 제어를하지 않는 read()write()단지에 open().
Pavel Šimerda

6
@Johnny : 그 당시 하드웨어가 얼마나 제한적 이었는지 잊었을 것입니다. 유닉스가 처음 구현 된 PDP-7은 (당 구글 당) 최대 64K의 RAM과 0.333MHz의 클럭을 가졌으며, 이는 오늘날 단순한 마이크로 컨트롤러보다 적습니다. 이러한 가비지 콜렉션을 수행하거나 시스템 코드를 사용하여 파일 액세스를 모니터하면 시스템이 무릎을 꿇을 수 있습니다.
jamesqf

답변:


60

데니스 리치에 언급 «유닉스 시간 공유 시스템의 진화»openclose함께 read, write그리고 creat처음부터 시스템에 존재했다.

나는없이 시스템을 생각 open하고 close상상할 수없는 것, 그러나 나는 디자인을 복잡하게 할 생각합니다. 일반적으로 하나의 호출이 아닌 여러 번의 읽기 및 쓰기 호출을 원하며 이는 UNIX가 시작된 RAM이 매우 제한적인 이전 컴퓨터에서 특히 그렇습니다. 현재 파일 위치를 유지하는 핸들이 있으면이를 단순화합니다. 만약 readwrite핸들을 반환해야했는데 핸들과 자신의 반환 상태 인 쌍을 반환해야했습니다. 쌍의 핸들 부분은 다른 모든 호출에 쓸모가 없으므로 배열이 어색합니다. 커서 상태를 커널에 남겨두면 버퍼링뿐만 아니라 효율성을 향상시킬 수 있습니다. 경로 조회와 관련된 비용도 있습니다. 손잡이를 사용하면 한 번만 지불하면됩니다. 또한 UNIX 월드 뷰의 일부 파일에는 파일 시스템 경로가 없거나 파일 시스템 경로가 없습니다 /proc/self/fd.


7
경로 조회 및 권한 확인 등의 비용은 매우 중요합니다. open/ 없이 시스템을 만들려면 파이프를 허용하는 close것과 같은 /dev/stdout것을 구현해야합니다 .
Peter Cordes

5
이것의 또 다른 측면은 파일을 열어 둘 때 다중 읽기를 사용할 때 동일한 파일에 대한 핸들을 유지할 수 있다는 것입니다. 그렇지 않으면, 다른 프로세스가 링크를 해제하고 동일한 이름의 파일을 다시 작성하는 경우가있을 수 있으며, 청크로 파일을 읽는 것은 사실상 일관되지 않을 수 있습니다. (일부는 파일 시스템에 따라 다를 수도 있습니다.)
Bruno

2
close ()없이 디자인했습니다. inode 번호와 오프셋을 read () 및 write ()에 전달합니다. 이름 확인이있는 곳이기 때문에 open () 없이는 쉽게 할 수 없습니다.
Joshua

3
@Joshua : 유닉스 파일 디스크립터는 파일 (inodes)을 참조하지 않고 파일 설명열기 때문에 그러한 시스템은 근본적으로 다른 의미를 갖습니다 .
R ..

@Joshua, 방금 이름 open()을 바꾸고 get_inode()전체 시스템을보다 견고하게 만들었습니다 (동일한 파일을 여러 위치에서 동시에 읽고 쓸 수 없음).
vonbrand

53

그런 다음 모든 readwrite호출은 각 작업에 대해이 정보를 전달해야합니다.

  • 파일의 이름
  • 파일의 권한
  • 발신자가 추가하거나 생성하는지 여부
  • 호출자가 파일 작업을 완료 했는지 여부 (사용되지 않는 읽기 버퍼를 버리고 쓰기 버퍼가 실제로 쓰기를 완료했는지 확인)

당신이 독립적 인 생각하든 전화를 open , read, writecloseI / O의 단일 목적과 간단합니다 메시지가 당신의 디자인 철학을 기반으로합니다. 유닉스 개발자는 모든 작업을 수행하는 단일 작업 (또는 프로그램)이 아닌 여러 가지 방식으로 결합 할 수있는 간단한 작업 및 프로그램을 사용하기로 결정했습니다.


호출자는 대부분의 경우 파일 내에서 원하는 오프셋을 지정해야합니다. 각 요청이 파일과 오프셋을 독립적으로 식별하는 것이 서버가 상태를 유지할 필요가 없기 때문에 도움이 될 수있는 상황 (예 : 데이터에 대한 액세스를 허용하는 UDP 프로토콜)이 있지만 일반적으로 서버를 보유하는 것이 더 편리합니다 파일 위치를 추적하십시오. 또한 다른 곳에서 언급 한 것처럼 파일을 작성하려는 코드는 종종 파일을 미리 잠그고 나중에 잠 가야합니다. 이러한 작업을 열기 / 닫기와 결합하는 것이 매우 편리합니다.
supercat 2019

5
"파일"은 처음에 이름이나 권한이 없을 수 있습니다. readwrite파일 시스템에 살고 파일로 제한하고, pjc50의 설명에 즉, 유닉스의 기본 설계 결정입니다되지 않습니다.
reinierpost

1
또한 여기서 읽을 수있는 파일에서 / 그것을 쓰기 - 시작, 끝, 또는 임의의 위치 (일반적으로 마지막 읽기 / 쓰기의 종료 후 즉시이 될를) - 커널 모드로와 (당신이 추적 모든 쓰기를 파일의 끝으로 보내십시오. 그렇지 않으면 파일은 시작 부분의 위치에서 열리고 각 읽기 / 쓰기로 진행되며 lseek) 로 이동할 수 있습니다.
Random832

51

파일 핸들의 개념은 파일 시스템의 일부가 아닌 것을 포함하여 "모든 것이 파일"인 UNIX의 디자인 선택 때문에 중요합니다. 테이프 드라이브, 키보드 및 스크린 (또는 텔레타이프), 펀치 카드 / 테이프 리더, 직렬 연결, 네트워크 연결 및 (주요 UNIX 발명)와 같은 "파이프"라는 다른 프로그램에 직접 연결합니다.

당신이 좋아하는 간단한 표준 UNIX 유틸리티의 많은 보면 grep특히 원래 버전에서, 당신은 그들이 호출을 포함하지 않는 것을 알 수 있습니다 open()close()하지만 단지 readwrite. 파일 핸들은 셸에 의해 프로그램 외부 에서 설정되고 시작될 때 전달됩니다. 따라서 프로그램은 파일 또는 다른 프로그램에 쓰는지 신경 쓸 필요가 없습니다.

뿐만 아니라 open, 파일 설명을 얻을 수있는 다른 방법은 socket, listen, pipe, dup, 및 파이프를 통해 파일 기술자를 보내는 매우 히스 로빈슨 메커니즘 : https://stackoverflow.com/questions/28003921/sending-file-descriptor-by-linux -소켓

편집 : 간접 계층과 이것이 O_APPEND가 현명하게 작동하게하는 방법을 설명하는 강의 노트 . inode 데이터를 메모리에 유지하면 시스템이 다음 쓰기 작업을 위해 다시 가져와야 할 필요가 없습니다.


1
또한 creat, 및 listen파일 디스크립터를 생성하지 않습니다,하지만 때 (그리고 경우) 듣기는 동안 요청이 들어 오면 accept만들고 새 (연결) 소켓의 파일 디스크립터를 반환합니다.
dave_thompson_085

18
이것이 정답입니다. 파일 디스크립터에 대한 유명한 (작은) 작업 세트는 데이터를 생성하거나 소비하는 모든 종류의 리소스에 대한 통합 API입니다. 이 개념은 매우 성공적입니다. 문자열 실제 위치 (URL은 누구입니까?)와 함께 자원 유형을 정의하는 구문을 가질 있지만 사용 가능한 RAM의 몇 퍼센트를 차지하는 문자열을 복사하려면 (PDP 7에서 16 kB는 무엇입니까?) .
피터-복원 모니카

낮은 수준의 호출과 셸이 동시에 개발 된 경우 일 수 있습니다. 그러나 pipe유닉스 개발이 시작된 몇 년 후 소개되었습니다.
Thomas Dickey

1
@Thomas Dickey : 파이프를 간단하게 확장 할 수 있었기 때문에 원래 디자인이 얼마나 좋은지를 보여줍니다. & c :-)
jamesqf

그러나 그 주장에 따라이 답변은 새로운 것을 제공하지 않습니다.
Thomas Dickey

10

open ()과 close ()는 각각 핸들을 만들고 파괴하기 때문에 대답은 '아니요'입니다. 예상치 못한 파싱을 통해 파일에 쓰는 다른 호출자 (예를 들어)가 예기치 않게 떠날 수 있기 때문에 특정 액세스 수준의 유일한 발신자임을 보장하려는 경우가 있습니다 (실제로 항상). 알 수없는 상태의 응용 프로그램 또는 라이브 록 또는 교착 상태 (예 : 식당 철학자 보조)로 연결됩니다.

이러한 고려 사항이 없어도 고려해야 할 성능 관련 사항이 있습니다. close ()는 파일 시스템이 (적절한 경우 또는 호출 한 경우) 사용중인 버퍼를 비우도록합니다. 인 메모리 스트림에 대한 여러 번의 연속 편집은 파일 시스템에 대한 본질적으로 관련이없는 읽기 / 쓰기-수정 사이클보다 훨씬 효율적입니다. 로컬 스토리지에서도 메모리는 일반적으로 대량 스토리지보다 훨씬 빠릅니다.


7

Open ()은 사용중인 파일을 잠그는 방법을 제공합니다. 파일이 자동으로 열리고, 읽히고 쓴 다음 OS에 의해 다시 닫히면 다른 응용 프로그램이 작업간에 해당 파일을 변경하는 것을 막을 수있는 것은 없습니다.

간단하게 관리 할 수 ​​있지만 (많은 시스템에서 비 독점 파일 액세스를 지원) 대부분의 응용 프로그램은 열려있는 파일이 변경되지 않는다고 가정합니다.


5

파일의 경로는 동일하게 유지된다고 가정하는 동안 이동 될 수 있습니다.


4

파일 시스템을 읽고 쓰는 작업에는 다양한 버퍼링 체계, OS 하우스 키핑, 저수준 디스크 관리 및 기타 여러 가지 잠재적 인 작업 포함될 있습니다. 따라서 이러한 유형의 후드 활동에 대한 조치 open()close()설정이 수행됩니다. 파일 시스템의 다른 구현은 필요에 따라 고도로 사용자 정의 될 수 있으며 여전히 호출 프로그램에 투명하게 남아 있습니다.

OS에 개 / 폐가없는 경우 with read또는를 사용 write하면 해당 파일 작업은 매번 초기화, 버퍼 플러시 / 관리 등을 수행해야합니다. 반복적 인 읽기 및 쓰기를 위해 많은 오버 헤드가 발생합니다.


open () 및 close ()는 파일에서 위치를 유지한다는 것을 잊지 마십시오 (다음 읽기 또는 다음 쓰기). 따라서 마지막 또는 read () 및 write ()에는 모든 매개 변수를 처리하는 구조체가 필요하거나 각 매개 변수에 대한 인수가 필요합니다. 구조를 만드는 것은 오픈과 동일하므로 (프로그래머 사이트) OS가 개방에 대해 알고 있다면 더 많은 이점이 있습니다.
Giacomo Catenazzi

1

유닉스 만트라는 "일을하는 한 가지 방법을 제공한다"는 뜻대로 결합 할 수있는 (재사용 가능한) 조각들로 "인수 화"하는 것을 의미한다. 즉,이 경우 파일 핸들의 생성과 삭제는 사용에서 분리됩니다. 파이프와 네트워크 연결을 통해 중요한 이점이 생겼습니다 (파일 핸들을 통해서도 조작되지만 다른 방식으로 생성됨). 파일 핸들을 전달할 수있는 것 (예를 들어, 파일을 자식 프로세스에 "열린 파일"로 exec(2)전달하고 파이프를 통해 관련없는 프로세스로 전달하는 것)은이 방법으로 만 가능합니다. 특히 보호 된 파일에 대한 제어 된 액세스를 제공하려는 경우. 예를 들어 열 수 있습니다/etc/passwd 쓰기 위해 파일을 열 수없는 자식 프로세스에 전달하십시오 (예, 이것이 우스운 예라는 것을 알고 더 현실적인 것으로 자유롭게 편집하십시오).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.