Input Stream 복제 방법
InputStream을 사용하여 메서드에 전달하여 처리한다.다른 방식에서도 같은 InputStream을 사용하지만 첫 번째 처리 후 InputStream이 메서드 내에서 닫힙니다.
InputStream을 복제하여 그를 닫는 메서드로 전송하려면 어떻게 해야 합니까?다른 해결책이 있나요?
EDIT: InputStream을 닫는 메서드는 lib의 외부 메서드입니다.나는 문을 닫거나 닫지 않을 수 없다.
private String getContent(HttpURLConnection con) {
InputStream content = null;
String charset = "";
try {
content = con.getInputStream();
CloseShieldInputStream csContent = new CloseShieldInputStream(content);
charset = getCharset(csContent);
return IOUtils.toString(content,charset);
} catch (Exception e) {
System.out.println("Error downloading page: " + e);
return null;
}
}
private String getCharset(InputStream content) {
try {
Source parser = new Source(content);
return parser.getEncoding();
} catch (Exception e) {
System.out.println("Error determining charset: " + e);
return "UTF-8";
}
}
같은 정보를 여러 번 읽어보고 싶은 경우 입력 데이터가 메모리에 들어갈 정도로 작을 경우,InputStream
ByteArrayOutputStream으로 이동합니다.
그런 다음 연결된 바이트 배열을 가져와 원하는 만큼 "클론된" 바이트 어레이 입력 스트림을 열 수 있습니다.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// Code simulating the copy
// You could alternatively use NIO
// And please, unlike me, do something about the Exceptions :D
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1 ) {
baos.write(buffer, 0, len);
}
baos.flush();
// Open new InputStreams using recorded bytes
// Can be repeated as many times as you wish
InputStream is1 = new ByteArrayInputStream(baos.toByteArray());
InputStream is2 = new ByteArrayInputStream(baos.toByteArray());
그러나 새 데이터를 수신하기 위해 원래 스트림을 열어 두어야 하는 경우 외부 콜을 추적해야 합니다.close()
예방할 필요가 있습니다.close()
어떻게든 불리지 않게 하려고요.
업데이트(2019):
Java 9 이후로는 중간 비트를 다음과 같이 대체할 수 있습니다.
ByteArrayOutputStream baos = new ByteArrayOutputStream();
input.transferTo(baos);
InputStream firstClone = new ByteArrayInputStream(baos.toByteArray());
InputStream secondClone = new ByteArrayInputStream(baos.toByteArray());
Apache를 사용하는 경우:
스트림이 닫히지 않도록 하는 래퍼입니다.이런 거 할 거예요.
InputStream is = null;
is = getStream(); //obtain the stream
CloseShieldInputStream csis = new CloseShieldInputStream(is);
// call the bad function that does things it shouldn't
badFunction(csis);
// happiness follows: do something with the original input stream
is.read();
복제할 수 없습니다.또한 데이터 소스의 종류에 따라 문제를 해결하는 방법이 달라집니다.
하나의 솔루션은 InputStream에서 모든 데이터를 바이트 배열로 읽은 후 해당 바이트 배열 주위에 ByteArrayInputStream을 생성하여 해당 입력 스트림을 메서드에 전달하는 것입니다.
Edit 1(편집 1): 즉, 다른 메서드에서도 같은 데이터를 읽어야 합니다.즉, 스트림을 "리셋"하려고 합니다.
스트림에서 읽어낸 데이터가 크다면 Apache Commons IO의 TeeInputStream을 사용하는 것이 좋습니다.이렇게 하면 입력을 복제하고 t'd 파이프를 클론으로 전달할 수 있습니다.
이것은 모든 상황에서 동작하는 것은 아니지만, FilterInputStream 클래스를 확장하고 외부 lib가 데이터를 읽을 때 필요한 바이트 처리를 수행합니다.
public class StreamBytesWithExtraProcessingInputStream extends FilterInputStream {
protected StreamBytesWithExtraProcessingInputStream(InputStream in) {
super(in);
}
@Override
public int read() throws IOException {
int readByte = super.read();
processByte(readByte);
return readByte;
}
@Override
public int read(byte[] buffer, int offset, int count) throws IOException {
int readBytes = super.read(buffer, offset, count);
processBytes(buffer, offset, readBytes);
return readBytes;
}
private void processBytes(byte[] buffer, int offset, int readBytes) {
for (int i = 0; i < readBytes; i++) {
processByte(buffer[i + offset]);
}
}
private void processByte(int readByte) {
// TODO do processing here
}
}
그럼 당신은 단순히 그 예시를 지나쳐요.StreamBytesWithExtraProcessingInputStream
입력 스트림을 통과했을 것입니다.원래 입력 스트림을 생성자 매개 변수로 사용합니다.
이 기능은 바이트 단위로 작동하므로 고성능이 필요한 경우에는 사용하지 마십시오.
UPD. 아까 댓글 확인해주세요.그것은 정확히 요구된 것이 아니다.
「 」를 사용하고 apache.commons
할 수 .IOUtils
.
사용할 수 있는 코드는 다음과 같습니다.
InputStream = IOUtils.toBufferedInputStream(toCopy);
고객의 상황에 적합한 완전한 예를 다음에 나타냅니다.
public void cloneStream() throws IOException{
InputStream toCopy=IOUtils.toInputStream("aaa");
InputStream dest= null;
dest=IOUtils.toBufferedInputStream(toCopy);
toCopy.close();
String result = new String(IOUtils.toByteArray(dest));
System.out.println(result);
}
이 코드에는 몇 가지 종속성이 필요합니다.
메이브
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
그라데
'commons-io:commons-io:2.4'
이 방법의 DOC 레퍼런스는 다음과 같습니다.
InputStream의 전체 내용을 가져오고 결과 InputStream과 동일한 데이터를 나타냅니다.이 방법은 다음과 같은 경우에 유용합니다.
소스 입력 스트림 속도가 느립니다.네트워크 리소스가 관련되어 있기 때문에 장시간 열어 둘 수 없습니다.네트워크 타임아웃이 관련되어 있습니다.
은 을 참조할 수 있습니다.IOUtils
여기: http://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/IOUtils.html#toBufferedInputStream(java.io.InputStream)
다음은 Kotlin과의 해결책입니다.
InputStream을 ByteArray에 복사할 수 있습니다.
val inputStream = ...
val byteOutputStream = ByteArrayOutputStream()
inputStream.use { input ->
byteOutputStream.use { output ->
input.copyTo(output)
}
}
val byteInputStream = ByteArrayInputStream(byteOutputStream.toByteArray())
글을 읽어야 한다면요.byteInputStream
번 콜 " " " , "byteInputStream.reset()
뭇매를 맞다
https://code.luasoftware.com/tutorials/kotlin/how-to-clone-inputstream/
아래 반에서 잘해야 합니다.인스턴스를 만들고 "멀티플리" 메서드를 호출하여 소스 입력 스트림과 필요한 복제 수를 제공하십시오.
중요: 클론된 모든 스트림을 개별 스레드로 동시에 소비해야 합니다.
package foo.bar;
import java.io.IOException;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InputStreamMultiplier {
protected static final int BUFFER_SIZE = 1024;
private ExecutorService executorService = Executors.newCachedThreadPool();
public InputStream[] multiply(final InputStream source, int count) throws IOException {
PipedInputStream[] ins = new PipedInputStream[count];
final PipedOutputStream[] outs = new PipedOutputStream[count];
for (int i = 0; i < count; i++)
{
ins[i] = new PipedInputStream();
outs[i] = new PipedOutputStream(ins[i]);
}
executorService.execute(new Runnable() {
public void run() {
try {
copy(source, outs);
} catch (IOException e) {
e.printStackTrace();
}
}
});
return ins;
}
protected void copy(final InputStream source, final PipedOutputStream[] outs) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
int n = 0;
try {
while (-1 != (n = source.read(buffer))) {
//write each chunk to all output streams
for (PipedOutputStream out : outs) {
out.write(buffer, 0, n);
}
}
} finally {
//close all output streams
for (PipedOutputStream out : outs) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
입력 스트림을 복제하려면 복제 중인 입력 스트림에 대한 자세한 지식이 필요하므로 복제하는 것이 좋습니다.이 문제를 해결하려면 동일한 소스에서 다시 읽는 새 입력 스트림을 만들어야 합니다.
Java 8 기능을 사용하면 다음과 같습니다.
public class Foo {
private Supplier<InputStream> inputStreamSupplier;
public void bar() {
procesDataThisWay(inputStreamSupplier.get());
procesDataTheOtherWay(inputStreamSupplier.get());
}
private void procesDataThisWay(InputStream) {
// ...
}
private void procesDataTheOtherWay(InputStream) {
// ...
}
}
할 수 인 효과가 . 즉, 입력 하면 입력 스트림이 생성되고, 입력 스트림이 생성됩니다.inputStreamSupplier
스트림 복제를 위해 두 번째 코드 경로를 유지할 필요가 없습니다.
한편 스트림에서 읽어들이는 비용이 많이 드는 경우(접속이 낮은 대역에서 실행되기 때문에), 이 방법을 사용하면 비용이 두 배로 증가합니다.을 로컬로 하고, 「」를 사용하는 할 수 .InputStream
현재 로컬리소스에 대응하고 있습니다.
예를 들어 를 확장합니다.
입력 스트림:클론 작성
bytes-Stream
및 에서 목록 컬렉션으로 복사본 수를 제공합니다.
public static List<InputStream> multiplyBytes(InputStream input, int cloneCount) throws IOException {
List<InputStream> copies = new ArrayList<InputStream>();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
copy(input, baos);
for (int i = 0; i < cloneCount; i++) {
copies.add(new ByteArrayInputStream(baos.toByteArray()));
}
return copies;
}
// IOException - If reading the Reader or Writing into the Writer goes wrong.
public static void copy(Reader in, Writer out) throws IOException {
try {
char[] buffer = new char[1024];
int nrOfBytes = -1;
while ((nrOfBytes = in.read(buffer)) != -1) {
out.write(buffer, 0, nrOfBytes);
}
out.flush();
} finally {
close(in);
close(out);
}
}
리더: 클론 작성
chars-Stream
및 에서 목록 컬렉션으로 복사본 수를 제공합니다.
public static List<Reader> multiplyChars(Reader reader, int cloneCOunt) throws IOException {
List<Reader> copies = new ArrayList<Reader>();
BufferedReader bufferedInput = new BufferedReader(reader);
StringBuffer buffer = new StringBuffer();
String delimiter = System.getProperty("line.separator");
String line;
while ((line = bufferedInput.readLine()) != null) {
if (!buffer.toString().equals(""))
buffer.append(delimiter);
buffer.append(line);
}
close(bufferedInput);
for (int i = 0; i < cloneCOunt; i++) {
copies.add(new StringReader(buffer.toString()));
}
return copies;
}
public static void copy(InputStream in, OutputStream out) throws IOException {
try {
byte[] buffer = new byte[1024];
int nrOfBytes = -1;
while ((nrOfBytes = in.read(buffer)) != -1) {
out.write(buffer, 0, nrOfBytes);
}
out.flush();
} finally {
close(in);
close(out);
}
}
완전한 예:
public class SampleTest {
public static void main(String[] args) throws IOException {
String filePath = "C:/Yash/StackoverflowSSL.cer";
InputStream fileStream = new FileInputStream(new File(filePath) );
List<InputStream> bytesCopy = multiplyBytes(fileStream, 3);
for (Iterator<InputStream> iterator = bytesCopy.iterator(); iterator.hasNext();) {
InputStream inputStream = (InputStream) iterator.next();
System.out.println("Byte Stream:"+ inputStream.available()); // Byte Stream:1784
}
printInputStream(bytesCopy.get(0));
//java.sql.Clob clob = ((Clob) getValue(sql)); - clob.getCharacterStream();
Reader stringReader = new StringReader("StringReader that reads Characters from the specified string.");
List<Reader> charsCopy = multiplyChars(stringReader, 3);
for (Iterator<Reader> iterator = charsCopy.iterator(); iterator.hasNext();) {
Reader reader = (Reader) iterator.next();
System.out.println("Chars Stream:"+reader.read()); // Chars Stream:83
}
printReader(charsCopy.get(0));
}
// Reader, InputStream - Prints the contents of the reader to System.out.
public static void printReader(Reader reader) throws IOException {
BufferedReader br = new BufferedReader(reader);
String s;
while ((s = br.readLine()) != null) {
System.out.println(s);
}
}
public static void printInputStream(InputStream inputStream) throws IOException {
printReader(new InputStreamReader(inputStream));
}
// Closes an opened resource, catching any exceptions.
public static void close(Closeable resource) {
if (resource != null) {
try {
resource.close();
} catch (IOException e) {
System.err.println(e);
}
}
}
}
언급URL : https://stackoverflow.com/questions/5923817/how-to-clone-an-inputstream
'programing' 카테고리의 다른 글
VueJs를 다른 컴포넌트(동일한 Axios에서 다른 컴포넌트로) (0) | 2022.06.09 |
---|---|
Vuex - 첫 번째 getter 호출 시 API에서 데이터를 로드한 후 상태에서 로드합니다. (0) | 2022.06.09 |
Vue에서 계산된 속성을 사용하여 v-bind 이미지 src를 만듭니다.JS (0) | 2022.06.07 |
vuex 상태를 서버와 동기화하기 위해 권장되는 전략 (0) | 2022.06.07 |
커스텀 Vue 디렉티브 내의 메서드를 호출하지 않고 식을 실행합니다. (0) | 2022.06.07 |