2011-07-26 3 views
11

Bytestring 라이브러리의 Data.ByteString.Lazy.Char8 라이브러리에 대한 질문이 있습니다. 특히, 내 질문에 다음과 같이 설명되어있는 readFile 함수를 관련이 있습니다.Windows에서 Data.ByteString.Lazy.Char8 개행 변환 --- 문서가 오도 된 것입니까?

ByteString lazily 전체 파일을 읽습니다. Windows에서 '텍스트 모드'를 사용하여 개행 문자를 해석하십시오.

이 함수는 '뉴 라인을 해석하기 위해 텍스트 모드를 사용합니다.'라는 주장에 관심이 있습니다. 그래서 openFile 기능 (openBinaryFile 반대)를 사용하고 있으며, :

-- | Read an entire file /lazily/ into a 'ByteString'. Use 'text mode' 
-- on Windows to interpret newlines 
readFile :: FilePath -> IO ByteString 
readFile f = openFile f ReadMode >>= hGetContents 

을 우리는 어떤 의미에서, 문서의 주장이 완벽하게 사실입니다 것을 볼 다음과 같이 함수에 대한 소스 코드는 파일에 개행 변환이 사용 가능하게됩니다.

하지만 파일은 hGetContents로 전달됩니다. 그러면 소스 코드 herehereData.ByteString.hGetNonBlocking이 호출됩니다.이 소스 코드는 Data.ByteString.hGet의 비 차단 버전입니다 (the documentation 참조). (최종적으로) Data.ByteString.hGetGHC.IO.Handle.hGetBuf (the documentation 또는 the source code 참조)이라고합니다. 이 기능의 documentation

hGetBuf는 손잡이가 현재 사용하고있는 어떤 TextEncoding 무시하고 기본 입출력 장치에서 직접 바이트를 읽어 있다고 말한다. 우리가 오히려 readBinaryFile보다 readFile을 사용하여 파일을 열었다는 사실이 관련이 있음을 시사

: 데이터는 질문의 시작 부분에 언급 된 문서의 주장에도 불구하고, 변환 줄 바꿈없이 읽을 수 있습니다.

그래서 질문의 핵심 : 1. 뭔가 빠졌습니까? 'Data.ByteString.Lazy.Char8.readFile에서 줄 바꿈을 해석하기 위해 Windows에서 텍스트 모드를 사용하는'진술은 사실입니까? 아니면 설명서가 오도 된 것입니까?

P. 테스트는 또한 적어도이 기능을 사용하면서 순진하게 사용하면 Windows에서 줄 바꿈을 수행하지 않는다는 것을 나타냅니다. 소스에 또 하나 개의 층을 파고

답변

4

FWIW, 패키지 관리자 인 Duncan Coutts는 매우 도움이되고 계몽적인 말로 응답했습니다. 나는 그 (것)들을 여기에 게시 할 수있는 그의 허가를 요청했지만, 잠시 동안 여기에 바꿔 치기가있다.

기본 사항은 문서가 한 번 정확했지만 지금은 그렇지 않다는 것입니다. 특히 윈도우에서 파일을 열면 운영 체제 자체에서 '텍스트'또는 '바이너리'모드로 열 수 있습니다.readFilereadBinaryFile의 차이는 을 사용하면 파일이 OS의 텍스트 모드로 열리고 Win32에서는 이진 모드로 열리는 것입니다. (그들은 모두 POSIX에서 동일하게 동작합니다.) OS의 바이너리 모드에서 파일을 열면 비공개 변환이없이 파일에서 읽을 수있는은 없습니다. 항상이 발생했습니다.

이렇게 설정하면 질문에 언급 된 설명서가 정확합니다. Data.ByteString.Lazy.Char8.readFileSystem.IO.readFile을 사용합니다. 이것은 OS가 파일 'Text'를 여는 것을 말하고, hGetBuf이 사용되었다고하더라도 개행 문자가 변환 될 것입니다.

그런 다음 나중에 Haskell의 System.IO을 처리하여 줄 바꿈 처리를보다 유연하게 만들었습니다. 특히 OS에 내장 된 개행 문자를 사용하여 파일을 읽을 수있는 기능이없는 POSIX OS에서 실행되는 Haskell 버전을 허용합니다 그럼에도 불구하고 Windows 스타일의 개행 문자로 파일을 읽는 것을 지원합니다. 두 OS 모두 Python-style 'universal' newline conversion을 지원할 수 있습니다. 이것은 다음을 의미합니다 :

  1. 개머리판 처리는 Haskell 라이브러리로 가져 왔습니다.
  2. readFile 또는 readBinaryFile과 상관없이 Windows에서 이진 모드로 열어 본 파일은 항상입니다.
  3. readFilereadBinaryFile 사이의 선택은 System.IO의 라이브러리 코드가 nativeNewlineMode 또는 noNewlineTranslation으로 설정되었는지 여부에 영향을 미칩니다. 그러면 Haskell 라이브러리 변환이 적절한 개행 변환을 수행합니다. 이제 universalNewlineMode을 요청할 수도 있습니다.

이 동일한 하스켈 System.IO에 내장 적절한 인코딩 지원있어 같이 시간 (보다는 입력 라틴 -1- 가정 단순히 처음 8 비트에 출력 자까지만 절단)에 대해 기록했다. 전반적으로, 그것은 좋은 일이었습니다.

는 는하지만, 비판적, 이제 라이브러리에 내장 된 새로운 개행 문자 변환은, hPutBuf가 --- 무엇에 영향을 결코

아마도 새로운 System.IO 기능을 구축하는 사람들이 생각했기 때문에 그 하나는 이진 벌금을 읽는 경우 어쨌든, 개행을 개입시키는 개행은 아마도 이 아니었다. 프로그래머가 원했던 것, 즉 실수였다. 그리고 실제로는 99 %의 경우입니다. 그러나이 경우 위의 문제가 발생합니다 :-)

Duncan은 라이브러리의 향후 릴리스에서이 용감한 새로운 세상을 반영하여 문서가 변경 될 것이라고합니다. 잠시 동안 there is a workaround listed in another answer to this question.

2

은 원시 바이트를 읽어 않습니다 보여줍니다 :

-- | 'hGetBuf' @hdl buf [email protected] reads data from the handle @[email protected] 
-- into the buffer @[email protected] until either EOF is reached or 
-- @[email protected] 8-bit bytes have been read. 
-- It returns the number of bytes actually read. This may be zero if 
-- EOF was reached before any data was read (or if @[email protected] is zero). 
-- 
-- 'hGetBuf' never raises an EOF exception, instead it returns a value 
-- smaller than @[email protected] 
-- 
-- If the handle is a pipe or socket, and the writing end 
-- is closed, 'hGetBuf' will behave as if EOF was reached. 
-- 
-- 'hGetBuf' ignores the prevailing 'TextEncoding' and 'NewlineMode' 
-- on the 'Handle', and reads bytes directly. 

hGetBuf :: Handle -> Ptr a -> Int -> IO Int 
hGetBuf h ptr count 
    | count == 0 = return 0 
    | count < 0 = illegalBufferSize h "hGetBuf" count 
    | otherwise = 
     wantReadableHandle_ "hGetBuf" h $ \ [email protected]__{..} -> do 
     flushCharReadBuffer h_ 
     [email protected]{ bufRaw=raw, bufR=w, bufL=r, bufSize=sz } 
      <- readIORef haByteBuffer 
     if isEmptyBuffer buf 
      then bufReadEmpty h_ buf (castPtr ptr) 0 count 
      else bufReadNonEmpty h_ buf (castPtr ptr) 0 count 
+0

Text.hs에 대한 합리적인 링크는 http://git.megacz.com/?p=ghc-base.git;a=tree;f=GHC/IO/Handle에 있습니다. hb = HEAD –

+0

코드가 원시 바이트를 읽었 음을 확인해 주셔서 감사합니다! (비록 내 발굴 후 99 % 확신 :-)) 이것은 분명히 문서 오류라고 생각 하는가, 아니면 텍스트 모드를 설정하는 것이 내가 모르는 다른 목적을 가지고 있는가? hGetBuf 사용? 문서 버그 인 경우 Data.ByteString.Lazy.Char8의 docstring을 변경하기위한 패치를 제출하는 절차는 무엇인지 알고 있습니까? –

+0

bytestring 패키지의 readFile에 대한 문서 오류와 같은 것 같습니다. 전자 메일 주소가있는 두 명의 관리자가 http://hackage.haskell.org/package/bytestring에 나열되어 있으며이 목록을 수정하면 도움이 될 수 있습니다. –

1

하지 요청으로 질문에 확실히 대답,하지만 난 다른 사람의 이익을 위해 다음과 같은 해결 방법을 언급 것이라고 생각하는 사람들 이 문제를 해결하고 Stack Overflow에서이 페이지를 찾으십시오. 그것은 stringsearch 패키지를 사용합니다.

import qualified Data.ByteString.Lazy as L 
import qualified Data.ByteString as B 
import qualified Data.ByteString.Lazy.Search as S 
import qualified System.IO 
import Control.Monad 

nativeCallsForConversion  = System.IO.nativeNewline == System.IO.CRLF 
readFileUniversalNewlineConversion = let 
    str_LF = B.pack [10] 
    str_CRLF = B.pack [13, 10] 
    in liftM (S.replace str_CRLF str_LF) . L.readFile 
readFileNativeNewlineConversion = 
    if nativeCallsForConversion 
    then readFileUniversalNewlineConversion 
    else L.readFile