Byłem zaskoczony, gdy dowiedziałem się dzisiaj, że nie mogę wyśledzić żadnego prostego sposobu zapisania zawartości InputStream
an OutputStream
w Javie. Oczywiście bajtowy kod bufora nie jest trudny do napisania, ale podejrzewam, że po prostu brakuje mi czegoś, co ułatwiłoby mi życie (i kod byłby wyraźniejszy).
Tak, podać InputStream
in
i OutputStream
out
czy istnieje prostszy sposób napisać co następuje?
byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
out.write(buffer, 0, len);
len = in.read(buffer);
}
Odpowiedzi:
Java 9
Od wersji Java 9
InputStream
udostępnia metodę wywoływanątransferTo
z następującym podpisem:Jak dokumentacji stanów,
transferTo
będzie:Aby więc zapisać zawartość Javy
InputStream
na anOutputStream
, możesz napisać:źródło
Files.copy
jak najwięcej. Jest zaimplementowany w kodzie natywnym i dlatego może być szybszy.transferTo
należy używać tylko wtedy, gdy oba strumienie nie są FileInputStream / FileOutputStream.Files.copy
nie obsługuje żadnych strumieni wejściowych / wyjściowych, ale jest specjalnie zaprojektowany dla strumieni plików .Jak wspomniano WMR,
org.apache.commons.io.IOUtils
Apache ma metodę o nazwie,copy(InputStream,OutputStream)
która robi dokładnie to, czego szukasz.Więc masz:
... w twoim kodzie.
Czy istnieje powód, dla którego unikasz
IOUtils
?źródło
in
iout
musi zostać zamknięty na końcu kodu w końcu blokuJeśli używasz Java 7, najlepszym rozwiązaniem jest Pliki (w standardowej bibliotece):
Edycja: Oczywiście jest to przydatne, gdy tworzysz jeden z InputStream lub OutputStream z pliku. Użyj,
file.toPath()
aby uzyskać ścieżkę z pliku.Aby zapisać do istniejącego pliku (np. Utworzonego za pomocą
File.createTempFile()
), musisz przekazaćREPLACE_EXISTING
opcję kopiowania (w przeciwnym razieFileAlreadyExistsException
zostanie wyrzucone):źródło
Files
NIE jest dostępny w Javie 1.7 w Androidzie . Uderzyło mnie to: stackoverflow.com/questions/24869323/...Files.copy()
dwa strumienie i jest tym, do czegoFiles.copy()
służą wszystkie pozostałe funkcje w celu wykonania rzeczywistej pracy kopiowania. Jest jednak prywatny (ponieważ na tym etapie tak naprawdę nie obejmuje ścieżek ani plików) i wygląda dokładnie tak , jak kod we własnym pytaniu OP (plus instrukcja return). Bez otwierania, bez zamykania, tylko pętla kopiująca.Myślę, że to zadziała, ale upewnij się, że to przetestujesz ... drobna „poprawa”, ale może to być trochę kosztowne pod względem czytelności.
źródło
while(len > 0)
zamiast!= -1
, ponieważ ten ostatni może również zwrócić 0, gdy używaszread(byte b[], int off, int len)
-method, która zgłasza wyjątek @out.write
InputStream
umową read read zwraca 0 dowolną liczbę razy. Zgodnie zOutputStream
umową metoda zapisu musi przyjmować długość 0 i powinna zgłaszać wyjątek tylko wtedy, gdylen
jest ujemna.while
afor
i umieszczając jedną ze zmiennych w sekcji inicjującej for: npfor (int n ; (n = in.read(buf)) != -1 ;) out.write(buf, 0, n);
. =)read()
może zwrócić zero tylko wtedy, gdy podasz długość zero, co byłoby błędem programowania i głupim warunkiem ciągłego zapętlania . Iwrite()
nie nie wyjątek jeśli podasz długość zerową.Korzystanie z Guawy
ByteStreams.copy()
:źródło
Files.copy
jak najwięcej. UżywajByteStreams.copy
tylko wtedy, gdy oba strumienie nie są FileInputStream / FileOutputStream.Prosta funkcja
Jeśli tylko trzeba to na pisanie
InputStream
DoFile
następnie można użyć tej prostej funkcji:źródło
close()
połączenia wfinally
blokach?Do
JDK
zastosowania tego samego kodu, więc wydaje się, że nie ma „łatwiejszy” sposób bez przylegający bibliotek strony trzeciej (która prawdopodobnie nic nie różni się w każdym razie zrobić). Poniższe dane są kopiowane bezpośrednio zjava.nio.file.Files.java
:źródło
PipedInputStream
iPipedOutputStream
powinien być używany tylko wtedy, gdy masz wiele wątków, jak zauważył Javadoc .Zauważ też, że strumienie wejściowe i wyjściowe nie zawijają żadnych przerw wątków za pomocą
IOException
s ... Więc powinieneś rozważyć włączenie polityki przerwania do swojego kodu:Byłby to użyteczny dodatek, jeśli spodziewasz się użyć tego interfejsu API do kopiowania dużych ilości danych lub danych ze strumieni, które utknęły na niedopuszczalnie długim czasie.
źródło
Dla tych, którzy korzystają z frameworka Spring, przydatna jest klasa StreamUtils :
Powyższe nie zamyka strumieni. Jeśli chcesz, aby strumienie były zamknięte po kopiowaniu, użyj klasy FileCopyUtils :
źródło
Nie ma sposobu, aby zrobić to o wiele łatwiej dzięki metodom JDK, ale jak już zauważył Apocalisp, nie jesteś jedyny z tym pomysłem: możesz użyć IOUtils z Jakarta Commons IO , ma również wiele innych przydatnych rzeczy, że IMO powinna faktycznie być częścią JDK ...
źródło
Korzystanie z Java7 i try-with-resources zawiera uproszczoną i czytelną wersję.
źródło
Oto, jak sobie radzę z najprostszą pętlą.
źródło
Użyj klasy Util Commons Net:
źródło
Bardziej minimalny fragment kodu IMHO (który również zawęża zakres zmiennej długości):
Na marginesie, nie rozumiem, dlaczego więcej osób nie używa
for
pętli, zamiast tego wybierawhile
wyrażenie z przypisywaniem i testowaniem, które przez niektórych jest uważane za „zły” styl.źródło
for(int n = 0; (n = in.read(buffer)) > 0;) { out.write(buffer, 0, n); }
To mój najlepszy strzał !!
I nie używaj,
inputStream.transferTo(...)
ponieważ jest zbyt ogólny. Wydajność kodu będzie lepsza, jeśli kontrolujesz pamięć bufora.Używam go z tą (poprawialną) metodą, gdy wiem z góry rozmiar strumienia.
źródło
Myślę, że lepiej jest użyć dużego bufora, ponieważ większość plików ma ponad 1024 bajty. Dobrą praktyką jest również sprawdzanie liczby odczytanych bajtów, aby były dodatnie.
źródło
Używam
BufferedInputStream
iBufferedOutputStream
do usunięcia semantyki buforowania z koduźródło
PipedInputStream i PipedOutputStream mogą się przydać, ponieważ możesz łączyć się ze sobą.
źródło
Innym możliwym kandydatem są narzędzia we / wy Guava:
http://code.google.com/p/guava-libraries/wiki/IOExplained
Myślałem, że skorzystam z nich, ponieważ Guava jest już niezwykle przydatny w moim projekcie, zamiast dodawać kolejną bibliotekę dla jednej funkcji.
źródło
copy
itoByteArray
metody w docs.guava-libraries.googlecode.com/git-history/release/javadoc/… (guava wywołuje strumienie wejściowe / wyjściowe jako „strumienie bajtów”, a czytelników / pisarzy jako „strumienieNiezbyt czytelny, ale skuteczny, nie ma zależności i działa z każdą wersją Java
źródło
!= -1
czy> 0
? Te prognozy nie są takie same.źródło
Wypróbuj Cactoos :
Więcej informacji tutaj: http://www.yegor256.com/2017/06/22/object-oriented-input-output-in-cactoos.html
źródło
możesz użyć tej metody
źródło
catch(Exception ex){}
- to jest na najwyższym poziomie