marcinek2929 napisał(a)
Nadal jest coś nie tak. Plik jpg 132kb poszedł bez problemu. Ale na 500 kb już się zawiesiło.
Taki mam kod:
ResultSet result = DBConnect.connect.createStatement().executeQuery("select zaw_Zawartosc from sys_Zawartosc where zaw_ID=12749;");
if(result.next()){
String outputFile = "temp.jpg";
int buffSize = 2048;
BufferedReader reader = new BufferedReader(result.getCharacterStream(1));
String inputString = "";
String line;
while ((line = reader.readLine()) != null) {
inputString += line;
}
byte[] bytes = new BigInteger(inputString, 16).toByteArray();
Inflater inflater = new Inflater();
inflater.setInput(bytes);
ByteArrayOutputStream out = new ByteArrayOutputStream(bytes.length * 2);
byte[] buffer = new byte[bytes.length * 2];
while (!inflater.finished()) {
int count = inflater.inflate(buffer);
out.write(buffer, 0, count);
}
FileOutputStream outFile = new FileOutputStream(outputFile);
outFile.write(out.toByteArray());
outFile.close();
out.close();
inflater.end();
}
result.close();
Kopiuj
W tym kodzie masz 2 problemy:
1. zamiana hex stringa na byte[] za pomoca new BigInteger - pomysl sobie, ze string ktory ma 500kb przedstawia wielka liczbe, i ty chcesz taka liczbe utworzyc - pomysl ile zajmuje parsowanie tego, obliczanie itp. Zamiast
byte[] bytes = new BigInteger(inputString, 16).toByteArray();
uzyj tej metody:
```java
public byte[] hexStringToByteArray(String s) {
byte[] bytes = new byte[s.length() / 2];
for (int i = 0, b = 0; i < s.length(); i += 2, ++b) {
byte first = (byte) Character.digit(s.charAt(i), 16);
byte second = (byte) Character.digit(s.charAt(i + 1), 16);
bytes[b] = (byte) (first << 4 | second);
}
return bytes;
}
Ta metoda tez ma slabosc i moze przestac dzialac dla wielkich plikow poniewaz opera sie na tym ze wczytujesz caly string (wspomniane 500kb) i nastepnie zamieniasz go na tablice bajtow (kolejnce 500kb), i trzymajac uchwyty do stringa i do tablicy bajtow uniemozliwiasz aby GC sprzatnal. Po zamianie stringa na byte[] ustaw inputString na null, umozliwisz GC sprzatniecie tego smiecia. A najlepiej jakbys zrobil tak, aby string byl wczytywany porcjami zamiast skladac go calego (porcja to np to co zwroci readLine(), i nastepnie pojedyncze porcje zamieniac na bajty (upewnij sie ze ma parzysta liczbe znakow, inaczej hexStringToBytes nie zadziala poprawnie), podawac do inflatera ktory tylko rozkoduja dana porcje, od razu ja zapisac do pliku. Inflater umie tak pracowac, poczytaj o metodzie needsInput i setInput. Nie jest to trywialne jak sie nigdy nie bawiles, a widac ze sie nie bawiles.
zapisujesz do ByteArrayOutputStream tylko po to zeby zaraz pozniej wszystko przerzucic do FileOutputStream - wiec po cholere ci ten tymczasowy ByteArrayOutputStream? Niech inflater od razu zapisuje do pliku.</li>
</ol>
Pamietaj, ze kody ktore tu dostajesz (np wspomniany BigInteger) to sa kody pisane na szybko, prototypowe, aby cos pokazac - nie sa kodami ktore mozna wrzucic na produkcje. Kolega iooi na pewno by inaczej zmienil hexString na byte[] gdyby musial to zrobic porzadnie. Mysl przy tym co czytasz, analizuj. Poza tym, spytales jak rozkodowac, dostales az nadto odpowiedzi, powinno wystarczyc juz to ze iooi powiedzial ze moje przypuszczenia sa sluszne. Jak chcesz kod ktory bedzie szybki, nie wywalal sie, gotowy na produkcje, wspieral gigabajtowe pliki itp to niestety ale bedziesz musial sypnac kasa zeby ktos taki kod napisal. To co masz teraz to zaciekawienie paru osob jakimstam wyzwaniem i proof of concept, nic wiecej.