जावा इनपुटस्ट्रीम की सामग्री को आउटपुटस्ट्रीम में लिखने का आसान तरीका


445

मैं आज लगता है कि मैं एक की सामग्री लिखने के लिए किसी भी आसान तरीका को ट्रैक नहीं कर सकता है आश्चर्यचकित था InputStreamएक करने के लिए OutputStreamजावा में। जाहिर है, बाइट बफर कोड को लिखना मुश्किल नहीं है, लेकिन मुझे संदेह है कि मैं बस कुछ याद कर रहा हूं, जिससे मेरा जीवन आसान हो जाएगा (और कोड स्पष्ट हो जाएगा)।

तो, InputStream inएक OutputStream out, और , वहाँ एक सरल तरीका निम्नलिखित लिखने के लिए है?

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
}

आपने एक टिप्पणी में उल्लेख किया है कि यह एक मोबाइल ऐप के लिए है। क्या यह देशी एंड्रॉयड है? यदि हां, तो मुझे बताएं और मैं एक और उत्तर पोस्ट करूंगा (यह किया जा सकता है एंड्रॉइड में कोड की एक एकल पंक्ति है)।
जाबरी

जवाबों:


182

जावा ९

जावा 9 के बाद से, निम्न हस्ताक्षर के साथ InputStreamएक विधि प्रदान करता है transferTo:

public long transferTo(OutputStream out) throws IOException

प्रलेखन राज्यों के रूप में , transferToहोगा:

इस इनपुट स्ट्रीम से सभी बाइट्स को पढ़ता है और दिए गए आउटपुट स्ट्रीम को बाइट्स को उस क्रम में लिखता है जिस क्रम में वे पढ़े जाते हैं। वापसी पर, यह इनपुट स्ट्रीम स्ट्रीम के अंत में होगा। यह विधि या तो धारा को बंद नहीं करती है।

यह विधि इनपुट स्ट्रीम, या आउटपुट स्ट्रीम से लेखन को अनिश्चित काल के लिए ब्लॉक कर सकती है। उस मामले के लिए व्यवहार जहां इनपुट और / या आउटपुट स्ट्रीम एसिंक्रोनस रूप से बंद है, या थ्रेड ट्रांसफर के दौरान बाधित है, अत्यधिक इनपुट और आउटपुट स्ट्रीम विशिष्ट है, और इसलिए निर्दिष्ट नहीं है

तो एक जावा की सामग्री लिखने के InputStreamलिए OutputStream, आप लिख सकते हैं:

input.transferTo(output);

11
आपको Files.copyजितना संभव हो उतना पसंद करना चाहिए । यह मूल कोड में लागू किया गया है और इसलिए यह तेज हो सकता है। transferToकेवल तभी उपयोग किया जाना चाहिए जब दोनों स्ट्रीम FileInputStream / FileOutputStream नहीं हैं।
४lov बजे

@ZhekaKozlov दुर्भाग्य से किसी भी इनपुट / आउटपुट स्ट्रीम को Files.copyहैंडल नहीं करता है लेकिन इसे विशेष रूप से फाइल स्ट्रीम के लिए डिज़ाइन किया गया है।
इम्पेलर

396

जैसा कि WMR ने उल्लेख किया है, org.apache.commons.io.IOUtilsअपाचे में से एक विधि है जिसे बुलाया जाता है copy(InputStream,OutputStream)जो वास्तव में आप देख रहे हैं।

मतलब आपके पास है:

InputStream in;
OutputStream out;
IOUtils.copy(in,out);
in.close();
out.close();

... आपके कोड में।

क्या कोई कारण है जिससे आप बच रहे हैं IOUtils?


170
मैं इसे इस मोबाइल ऐप के लिए टाल रहा हूं क्योंकि मैं इसका निर्माण कर रहा हूं क्योंकि यह कोड के 5 लाइनों को बचाने के लिए ऐप के आकार को कम कर देगा।
जेरेमी लोगन

36
यह शायद उल्लेख के लायक है inऔर outकोड के अंत में बंद होना चाहिए
बेसजेरो

24
@basZero या संसाधन ब्लॉक के साथ एक कोशिश का उपयोग कर।
वारेन ड्यू

1
या आप सिर्फ अपनी कॉपी (इन, आउट) रैपर लिख सकते हैं ... (कम समय में
लगेंगे

1
यदि आप पहले से ही अमरूद पुस्तकालय का उपयोग कर रहे हैं, तो बेट्स ने बाइटस्ट्रीम क्लास की सिफारिश की है। IOUtils जैसा करता है, वैसा ही होता है, लेकिन कॉमन्स IO को अपने प्रोजेक्ट में शामिल करने से बचता है।
जिम टफ

328

यदि आप जावा 7 का उपयोग कर रहे हैं, तो फ़ाइलें (मानक पुस्तकालय में) सबसे अच्छा तरीका है:

/* You can get Path from file also: file.toPath() */
Files.copy(InputStream in, Path target)
Files.copy(Path source, OutputStream out)

संपादित करें: बेशक यह उपयोगी है जब आप फ़ाइल से InputStream या OutputStream बनाते हैं। file.toPath()फ़ाइल से पथ प्राप्त करने के लिए उपयोग करें ।

एक मौजूदा फ़ाइल में लिखने के लिए (जैसे एक के साथ बनाया गया File.createTempFile()), आपको REPLACE_EXISTINGकॉपी विकल्प (अन्यथा FileAlreadyExistsExceptionफेंक दिया जाता है) पास करना होगा:

Files.copy(in, target, StandardCopyOption.REPLACE_EXISTING)

26
मुझे नहीं लगता कि यह वास्तव में समस्या का हल है क्योंकि एक छोर एक रास्ता है। जब तक आप किसी फ़ाइल के लिए एक पथ पा सकते हैं, जहाँ तक मुझे पता है कि आप किसी भी सामान्य स्ट्रीम के लिए एक प्राप्त नहीं कर सकते हैं (जैसे कि नेटवर्क पर एक)।
मैट शेपर्ड

4
CopyOptions मनमाना है! आप चाहें तो इसे यहां रख सकते हैं।
user1079877

4
अब यह वही है जिसकी मुझे तलाश थी! बचाव के लिए JDK, किसी अन्य पुस्तकालय की आवश्यकता नहीं है
डॉन चीडल

7
FYI करें, Android के जावा 1.7 Filesमें उपलब्ध नहीं है । मैं इस से लड़खड़ा गया: stackoverflow.com/questions/24869323/…
जोशुआ पिंटर

23
स्पष्ट रूप से, जेडीके के पास भी Files.copy()दो धाराएँ हैं, और यह कि Files.copy()नकल के वास्तविक कार्य को करने के लिए अन्य सभी कार्य आगे हैं। हालाँकि, यह निजी है (क्योंकि यह वास्तव में उस स्तर पर पथ या फ़ाइलों को शामिल नहीं करता है), और ओपी के स्वयं के प्रश्न (प्लस रिटर्न स्टेटमेंट) में कोड जैसा दिखता है । कोई उद्घाटन, कोई समापन नहीं, सिर्फ एक कॉपी लूप।
तिवारी सेगा

102

मुझे लगता है कि यह काम करेगा, लेकिन इसका परीक्षण करना सुनिश्चित करें ... मामूली "सुधार", लेकिन यह पठनीयता पर थोड़ा सा खर्च हो सकता है।

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}

26
मेरा सुझाव है कि कम से कम 10KB से 100KB के बफर का उपयोग करें। यह ज्यादा नहीं है और बड़ी मात्रा में डेटा की जबरदस्त नकल कर सकता है।
आरोन दिगुल्ला

6
आप while(len > 0)इसके बजाय कहना चाह सकते हैं != -1, क्योंकि उत्तरार्द्ध 0 भी लौट सकता है जब read(byte b[], int off, int len)-मिथोड का उपयोग करते हुए, जो एक अपवाद को फेंकता है @out.write
phil294

12
@ बलौनिर: यह गलत होगा, क्योंकि यह InputStreamकिसी भी समय 0 को वापस पढ़ने के लिए अनुबंध के अनुसार पूरी तरह से कानूनी है। और OutputStreamअनुबंध के अनुसार , लिखने की विधि को 0 की लंबाई स्वीकार करनी चाहिए, और lenनकारात्मक होने पर केवल एक अपवाद फेंकना चाहिए ।
क्रिस्टोफर हैमरस्ट्रॉम

1
आप एक init सेक्शन के whileलिए a को बदलकर forऔर किसी एक चर को डालकर एक लाइन को बचा सकते हैं : जैसे for (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);,। =)
euroburɳ

1
@ बल्लहिम read()केवल शून्य वापस कर सकता है यदि आप शून्य की लंबाई की आपूर्ति करते हैं, जो एक प्रोग्रामिंग त्रुटि होगी, और उस पर लूप करने के लिए एक बेवकूफ स्थिति। और write()करता नहीं एक अपवाद यदि आप एक शून्य लम्बाई प्रदान फेंक देते हैं।
लोर्ने की

54

अमरूद का उपयोग ByteStreams.copy():

ByteStreams.copy(inputStream, outputStream);

11
उसके बाद धाराओं को बंद करने के लिए मत भूलना!
वंडरसकेबो

यह सबसे अच्छा जवाब है यदि आप पहले से ही अमरूद का उपयोग कर रहे हैं जो मेरे लिए अपरिहार्य हो गया है।
हांग

1
@ आप Files.copyजितना संभव हो उतना उपयोग करें । ByteStreams.copyयदि दोनों स्ट्रीम FileInputStream / FileOutputStream नहीं हैं, तो ही उपयोग करें ।
झक्काझोजोव

@ZhekaKozlov टिप के लिए धन्यवाद। मेरे मामले में, इनपुट स्ट्रीम एक एंड्रॉइड ऐप के संसाधन (ड्रॉबल) से है।
हांग

26

सरल कार्य

यदि आपको केवल एक लिखने के लिए इसकी आवश्यकता InputStreamहै Fileतो आप इस सरल फ़ंक्शन का उपयोग कर सकते हैं:

private void copyInputStreamToFile( InputStream in, File file ) {
    try {
        OutputStream out = new FileOutputStream(file);
        byte[] buf = new byte[1024];
        int len;
        while((len=in.read(buf))>0){
            out.write(buf,0,len);
        }
        out.close();
        in.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

4
शानदार समारोह, धन्यवाद। क्या आपको close()कॉल को finallyब्लॉक में रखना होगा , हालाँकि?
जोशुआ पिंटर

@JoshPinter यह चोट नहीं करेगा।
जॉर्डन लाएप्राइज़

3
आप शायद दोनों को एक अंतिम ब्लॉक में शामिल करें और वास्तविक कार्यान्वयन में अपवादों को न निगलें। इसके अलावा, एक इनपुटस्ट्रीम को एक विधि में बंद करना कभी-कभी कॉलिंग विधि द्वारा अप्रत्याशित होता है, इसलिए किसी को यह विचार करना चाहिए कि क्या यह ऐसा व्यवहार है जो वे चाहते हैं।
सेल स्केग्स

2
जब IOException पर्याप्त होती है तो अपवाद को क्यों पकड़ते हैं?
प्रभाकर

18

JDKएक ही कोड का उपयोग करता है तो ऐसा लगता है कि क्लंकी तृतीय पक्ष पुस्तकालयों के बिना कोई "आसान" तरीका नहीं है (जो शायद किसी भी तरह से कुछ भी नहीं करते हैं)। निम्नलिखित को सीधे कॉपी किया गया है java.nio.file.Files.java:

// buffer size used for reading and writing
private static final int BUFFER_SIZE = 8192;

/**
  * Reads all bytes from an input stream and writes them to an output stream.
  */
private static long copy(InputStream source, OutputStream sink) throws IOException {
    long nread = 0L;
    byte[] buf = new byte[BUFFER_SIZE];
    int n;
    while ((n = source.read(buf)) > 0) {
        sink.write(buf, 0, n);
        nread += n;
    }
    return nread;
}

2
ऐ। शर्म आनी चाहिए यह विशेष रूप से निजी है और कोई दूसरा विकल्प नहीं है, लेकिन इसे अपनी उपयोगिताओं की कक्षा में कॉपी करने के लिए, क्योंकि यह संभव है कि आप फ़ाइलों के साथ काम नहीं कर रहे हैं, बल्कि एक ही बार में 2 सॉकेट।
ड्रैगस

17

PipedInputStreamऔर PipedOutputStreamकेवल तब उपयोग किया जाना चाहिए जब आपके पास कई धागे हों, जैसा कि जावदोक ने नोट किया था

इसके अलावा, ध्यान दें कि इनपुट स्ट्रीम और आउटपुट स्ट्रीम IOExceptionएस के साथ किसी भी थ्रेड रुकावट को लपेटते नहीं हैं ... इसलिए, आपको अपने कोड में एक रुकावट नीति को शामिल करने पर विचार करना चाहिए:

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
    if (Thread.interrupted()) {
        throw new InterruptedException();
    }
}

यह एक उपयोगी जोड़ होगा यदि आप इस एपीआई का उपयोग बड़ी मात्रा में डेटा, या उन धाराओं के डेटा की प्रतिलिपि बनाने के लिए करते हैं जो असहनीय रूप से लंबे समय तक अटक जाते हैं।


14

जो लोग स्प्रिंग फ्रेमवर्क का उपयोग करते हैं उनके लिए एक उपयोगी स्ट्रीमयूटिल्स क्लास है:

StreamUtils.copy(in, out);

उपरोक्त धाराओं को बंद नहीं करता है। यदि आप चाहते हैं कि प्रतिलिपि के बाद धाराएँ बंद हो जाएं, तो इसके बजाय FileCopyUtils वर्ग का उपयोग करें:

FileCopyUtils.copy(in, out);

8

JDK विधियों के साथ इसे बहुत आसान करने का कोई तरीका नहीं है, लेकिन जैसा कि Apocalisp ने पहले ही नोट किया है, आप इस विचार के साथ एक ही नहीं हैं: आप जकार्ता कॉमन्स IO से IOUtils का उपयोग कर सकते हैं , इसमें कई अन्य उपयोगी चीजें भी हैं। IMO वास्तव में JDK का हिस्सा होना चाहिए ...


6

Java7 और try-with-resource का उपयोग करना , एक सरलीकृत और पठनीय संस्करण के साथ आता है।

try(InputStream inputStream = new FileInputStream("C:\\mov.mp4");
    OutputStream outputStream = new FileOutputStream("D:\\mov.mp4")) {

    byte[] buffer = new byte[10*1024];

    for (int length; (length = inputStream.read(buffer)) != -1; ) {
        outputStream.write(buffer, 0, length);
    }
} catch (FileNotFoundException exception) {
    exception.printStackTrace();
} catch (IOException ioException) {
    ioException.printStackTrace();
}

3
लूप के अंदर फ्लशिंग अत्यधिक प्रति-उत्पादक है।
Lorne

5

यहाँ आता है कि मैं कैसे सरलतम पाश के साथ कर रहा हूँ।

private void copy(final InputStream in, final OutputStream out)
    throws IOException {
    final byte[] b = new byte[8192];
    for (int r; (r = in.read(b)) != -1;) {
        out.write(b, 0, r);
    }
}

4

कॉमन्स नेट के यूटिल क्लास का उपयोग करें:

import org.apache.commons.net.io.Util;
...
Util.copyStream(in, out);

3

एक IMHO अधिक न्यूनतम स्निपेट (वह भी अधिक संकीर्ण रूप से लंबाई वाले स्कोप):

byte[] buffer = new byte[2048];
for (int n = in.read(buffer); n >= 0; n = in.read(buffer))
    out.write(buffer, 0, n);

एक साइड नोट के रूप में, मुझे समझ में नहीं आता है कि अधिक लोग forलूप का उपयोग क्यों नहीं करते हैं , इसके बजाय whileएक असाइन-एंड-टेस्ट अभिव्यक्ति के साथ चयन करने के लिए जिसे कुछ लोगों द्वारा "खराब" शैली के रूप में माना जाता है।


1
आपका सुझाव पहली यात्रा पर 0-बाइट लिखने का कारण बनता है। शायद कम से कम करते हैं:for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
ब्रायन डी अल्विस

2
@BriandeAlwis आप पहली यात्रा गलत होने के बारे में सही हैं। कोड तय किया गया है (अपने सुझाव की तुलना में एक क्लीनर तरीके से IMHO) - संपादित कोड देखें। देखभाल के लिए Thx।
बोहेमियन

3

यह मेरा सबसे अच्छा शॉट है !!

और उपयोग न करें inputStream.transferTo(...)क्योंकि बहुत सामान्य है। यदि आप अपनी बफर मेमोरी को नियंत्रित करते हैं तो आपका कोड प्रदर्शन बेहतर होगा।

public static void transfer(InputStream in, OutputStream out, int buffer) throws IOException {
    byte[] read = new byte[buffer]; // Your buffer size.
    while (0 < (buffer = in.read(read)))
        out.write(read, 0, buffer);
}

जब मैं धारा के आकार को पहले से जानता हूं तो मैं इसे (कामचलाऊ) विधि से उपयोग करता हूं।

public static void transfer(int size, InputStream in, OutputStream out) throws IOException {
    transfer(in, out,
            size > 0xFFFF ? 0xFFFF // 16bits 65,536
                    : size > 0xFFF ? 0xFFF// 12bits 4096
                            : size < 0xFF ? 0xFF // 8bits 256
                                    : size
    );
}

2

मुझे लगता है कि एक बड़े बफर का उपयोग करना बेहतर है, क्योंकि अधिकांश फाइलें 1024 बाइट्स से अधिक हैं। सकारात्मक होने के लिए रीड बाइट्स की संख्या की जांच करना भी एक अच्छा अभ्यास है।

byte[] buffer = new byte[4096];
int n;
while ((n = in.read(buffer)) > 0) {
    out.write(buffer, 0, n);
}
out.close();

4
एक बड़े बफर का उपयोग करना वास्तव में एक अच्छा विचार है लेकिन इसलिए नहीं कि फाइलें ज्यादातर> 1k हैं, यह सिस्टम कॉल की लागत को परिशोधन करने के लिए है।
लोरेन

1

मैं का उपयोग करें BufferedInputStreamऔर BufferedOutputStreamकोड से बफरिंग अर्थ विज्ञान दूर करने के लिए

try (OutputStream out = new BufferedOutputStream(...);
     InputStream in   = new BufferedInputStream(...))) {
  int ch;
  while ((ch = in.read()) != -1) {
    out.write(ch);
  }
}

Is कोड से बफ़रिंग शब्दार्थों को हटाना ’एक अच्छा विचार क्यों है?
को लोर्ने

2
इसका मतलब है कि मैं अपने आप को बफरिंग तर्क नहीं लिखता हूं, मैं जेडडीके में निर्मित एक का उपयोग करता हूं जो आमतौर पर काफी अच्छा होता है।
आर्किमिडीज ट्रैजानो

0

PipedInputStream और PipedOutputStream कुछ काम की हो सकती हैं, क्योंकि आप एक को दूसरे से जोड़ सकते हैं।


1
यह सिंगल-थ्रेडेड कोड के लिए अच्छा नहीं है क्योंकि यह गतिरोध कर सकता है; इस प्रश्न को देखें stackoverflow.com/questions/484119/…
Raekye

2
कुछ काम का हो सकता है कैसे? उसके पास पहले से ही एक इनपुट स्ट्रीम और एक आउटपुट स्ट्रीम है। कैसे एक दूसरे को जोड़ने में मदद करेगा बिल्कुल?
लोर्न

0

एक अन्य संभावित उम्मीदवार अमरूद I / O उपयोगिताओं हैं:

http://code.google.com/p/guava-libraries/wiki/IOExplained

मैंने सोचा कि मैं इनका उपयोग करूँगा क्योंकि अमरूद मेरी परियोजना में पहले से ही काफी उपयोगी है, बजाय एक समारोह के लिए एक और पुस्तकालय जोड़ने के बजाय।


कर रहे हैं copyऔर toByteArrayमें तरीकों docs.guava-libraries.googlecode.com/git-history/release/javadoc/... (अमरूद इनपुट कॉल / आउटपुट के रूप में "बाइट धाराओं" और "चार धाराओं" पाठकों / लेखकों धाराओं)
Raekye

यदि आप पहले से ही अमरूद पुस्तकालयों का उपयोग करते हैं, तो यह एक अच्छा विचार है, लेकिन यदि नहीं, तो वे हजारों तरीकों से एक विशाल पुस्तकालय हैं, जिसमें 'google-way-of-do-doing-everything-different-to-standard' है। मैं उनसे दूर रहना चाहता हूं
रूबल

"विशाल"? 2.7MB निर्भरता के एक बहुत छोटे सेट के साथ, और एक एपीआई जो ध्यान से कोर JDK की नकल से बचा जाता है।
एड्रियन बेकर

0

बहुत पठनीय नहीं है, लेकिन प्रभावी है, कोई निर्भरता नहीं है और किसी भी जावा संस्करण के साथ चलता है

byte[] buffer = new byte[1024];
for (int n; (n = inputStream.read(buffer)) != -1; outputStream.write(buffer, 0, n));

!= -1या > 0? उन विधेय समान नहीं हैं।
इम्पेलर

! = -1 का मतलब फाइल का अंत नहीं है। यह एक पुनरावृत्ति नहीं है, बल्कि भेस में एक लूप-डू-लूप है: जबकि ((n = inputStream.read (बफर))! = -1) do {outputStream.write (बफर, 0, n)}
IPP Nerf

-1
public static boolean copyFile(InputStream inputStream, OutputStream out) {
    byte buf[] = new byte[1024];
    int len;
    long startTime=System.currentTimeMillis();

    try {
        while ((len = inputStream.read(buf)) != -1) {
            out.write(buf, 0, len);
        }

        long endTime=System.currentTimeMillis()-startTime;
        Log.v("","Time taken to transfer all bytes is : "+endTime);
        out.close();
        inputStream.close();

    } catch (IOException e) {

        return false;
    }
    return true;
}

4
क्या आप कृपया बता सकते हैं कि यह सही उत्तर क्यों है?
rfornal


-6

आप इस विधि का उपयोग कर सकते हैं

public static void copyStream(InputStream is, OutputStream os)
 {
     final int buffer_size=1024;
     try
     {
         byte[] bytes=new byte[buffer_size];
         for(;;)
         {
           int count=is.read(bytes, 0, buffer_size);
           if(count==-1)
               break;
           os.write(bytes, 0, count);
         }
     }
     catch(Exception ex){}
 }

6
catch(Exception ex){}- यह
नोच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.