2011-05-20 77 views
4

我有一段代碼讀取InputStream和寫的內容爲OutputStream更好的Java循環?

BufferedInputStream in = new BufferedInputStream(...); 
FileOutputStream outStream = new FileOutputStream outStream(...); 

int read = in.read(buffer, 0, bufferSize); 
while (read != -1) { 
    outStream.write(buffer, 0, read); 
    read = in.read(buffer, 0, bufferSize); 
} 

它的工作原理,但我不喜歡它,因爲變量read聲明退出循環,並read()方法被寫兩次。 修訂版:

for (int read = 0; read != -1; read = in.read(buffer, 0, bufferSize)) { 
     outStream.write(buffer, 0, read); 
} 

它看起來更好,但還不夠好,因爲第一次迭代是無用的(也許是有害的)與讀= 0。

你有更好的解決方案嗎?

+3

IMHO第一版本比所述第二版本更具有可讀性。 – 2011-05-20 11:49:45

+2

或者你可以使用commons-io並用'IOUtils.copy(in,outStream)替換整個東西;' – stevevls 2011-05-20 11:53:00

回答

10

個人而言,我打破常規規則「沒有在條件副作用」對於這樣的事情:

int bytesRead; 
while ((bytesRead = in.read(buffer, 0, bufferSize)) != -1) 
{ 
    outStream.write(buffer, 0, bytesRead); 
} 

編輯:如前所述,它確實涉及聲明read外循環,但它只呼叫read()一次。我從來沒有發現它是一個問題 - 雖然我通常傾向於儘可能使用範圍儘可能小的變量來聲明變量,但這更像是一種普遍的清潔工作。如果你想進一步限制範圍,你可以把整個事情放在大括號中,或者將它提取到自己的方法,就像艾倫的方法。以下是我如何實現它:

public static void copyStream(InputStream input, OutputStream output) 
    throws IOException { 
    byte[] buffer = new byte[1024 * 16]; // Reasonable general size 

    int bytesRead; 
    while ((bytesRead = in.read(buffer, 0, buffer.length)) != -1) { 
    outStream.write(buffer, 0, bytesRead); 
    } 
} 

或者,您可以提供緩衝區長度作爲參數。請注意,這現在可以進入實用程序庫,並且您不需要再次編寫代碼。

或者,你可以使用一個事實,即它在其他工具庫已經上市,如GuavaByteStreams.copy

+0

這仍然需要'bytesRead'在循環之外聲明,這是明確不需要的。 – 2011-05-20 12:29:43

+0

好吧,這個答案與Mat(和幾乎同時)中的答案基本相同。但爲什麼這個人得到更多的投票?只因爲它是喬恩?或者你讀過我沒看過的東西? – chance 2011-05-20 12:31:02

+0

@Alan:我錯過了那一點。將編輯。 – 2011-05-20 12:32:33

2

這種形式是相當平常:

while ((read = in.read(buffer, 0, bufferSize)) != -1) { 
    ... 
} 

但出於清楚IMO那麼好。

+0

和讀取的varibale必須定義在循環之外。 – chance 2011-05-20 11:49:32

+0

我的第二個版本不推薦,是嗎? – chance 2011-05-20 11:53:29

+1

@wang:在我看來,它的可讀性更差,你指出第一次迭代是錯誤的是正確的。這個版本很平常,你會看到很多,所以其他人閱讀你的代碼不應該太困惑。 – Mat 2011-05-20 11:56:37

3

你可以這樣來做:

BufferedInputStream in = new BufferedInputStream(...); 
FileOutputStream outStream = new FileOutputStream outStream(...); 

while (true) { // can i use for(;;) in Java ??? 
    int read = in.read(buffer, 0, bufferSize); 
    if (read == -1) break; 
    outStream.write(buffer, 0, read); 
} 

它採用了break,雖然。有人說break不好/不太好風格。

+1

我喜歡這個:) – chance 2011-05-20 11:59:49

+0

我的老cs-teacher總是告訴我:*「就像是彈出座位的飛機一樣」*。恕我直言:這取決於循環。在這種情況下,使用break並沒有任何意義,while是更好的選擇(請參閱其他答案)。 – 2011-05-20 12:01:17

+0

@Simon:這裏不是'break'一種[guard clause](http://www.refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html)? – chance 2011-05-20 12:07:10

3

這並不輝煌,但用一個簡單的塊,你可以停止從方法後來被訪問的read變量:

BufferedInputStream in = new BufferedInputStream(...); 
FileOutputStream outStream = new FileOutputStream outStream(...); 

{ 
    int read = in.read(buffer, 0, bufferSize); 
    while (read != -1) 
    { 
     outStream.write(buffer, 0, read); 
     read = in.read(buffer, 0, bufferSize); 
    } 
} 

// ...rest of your code 

...但我同意,我也經常想了一會兒循環,其中要測試的值在循環內初始化。據我所知,這是不可能的。

另一種方式來做到這一點是利用extract method design pattern拉出該循環中,以一個完全獨立的方法,即

public void yourMethod() { 
    BufferedInputStream in = new BufferedInputStream(...); 
    FileOutputStream outStream = new FileOutputStream outStream(...); 

    this.writeToOutputStream(in, outStream); 
} 

private void writeToOutputStream(InputStream in, OutputStream outStream) { 
    int read = in.read(buffer, 0, bufferSize); 
    while (read != -1) 
    { 
     outStream.write(buffer, 0, read); 
     read = in.read(buffer, 0, bufferSize); 
    } 
} 
+0

相關知識模式:) – chance 2011-05-20 12:26:31