Nasıl verilen bayt dizisi başladığı (Birinci oluşumu) System.Stream konumunu bulmanın en iyi yolu nedir sizce başlar PS En basit ama en hızlı çözüm tercih edilir. :)iyi yolu
iyi yolu
cevap
çözümdür.
3.050 KB
ve 38803 lines
olan bir ASCII dosyasıyla bazı karşılaştırmalar yaptım. Dosyanın son satırında byte
array
22 bytes
aramasında sonuç yaklaşık 2.28
saniye (yavaş/eski bir makinede) elde ettim.
public static long FindPosition(Stream stream, byte[] byteSequence)
{
if (byteSequence.Length > stream.Length)
return -1;
byte[] buffer = new byte[byteSequence.Length];
using (BufferedStream bufStream = new BufferedStream(stream, byteSequence.Length))
{
int i;
while ((i = bufStream.Read(buffer, 0, byteSequence.Length)) == byteSequence.Length)
{
if (byteSequence.SequenceEqual(buffer))
return bufStream.Position - byteSequence.Length;
else
bufStream.Position -= byteSequence.Length - PadLeftSequence(buffer, byteSequence);
}
}
return -1;
}
private static int PadLeftSequence(byte[] bytes, byte[] seqBytes)
{
int i = 1;
while (i < bytes.Length)
{
int n = bytes.Length - i;
byte[] aux1 = new byte[n];
byte[] aux2 = new byte[n];
Array.Copy(bytes, i, aux1, 0, n);
Array.Copy(seqBytes, aux2, n);
if (aux1.SequenceEqual(aux2))
return i;
i++;
}
return i;
}
Gelecekte başvurmak için 'PadLeftSequence',' SequenceEqual '' false değerini döndüren ilk eşleşen olmayan baytı arar. Benim için bir mikro-optimizasyon gibi görünüyor, çünkü birisi bir "SequenceEqual" 'ın bir maçtan erken geri dönmesini bekliyordu. Feragatname: Herhangi bir ölçüm yapmadım, bu sadece bir fikir. –
sadece dizilim bir uzunluk çoğaltmasının dizinindeyse işe yaramaz mı? Dizin 4'te 6 baytlık bir sekme bulunmayacak mı? – YoniXw
Temel olarak, arabellek byteSequence
ile aynı boyutta tutmanız gerekir, böylece akıştaki "sonraki bayt" öğesinin eşleştiğini gördükten sonra kalanını kontrol edebilirsiniz, ancak yine de geri dönebilirsiniz. gerçek bir eşleşme değilse "sonraki ama bir" bayt.
O biraz destek ne yaparsanız yapın olması olasıdır
, dürüst olmak gerekirse :(Eğer bayt başka dizisi gibi akışını ele alırsanız, bir dize arama yaptıklarını gibi, sadece arama yapamaz. Wikipedia sahiptir Bunun için harika bir makale Boyer-Moore, bunun için iyi ve basit bir algoritmadır.
İşte, Java'da bir araya getirdiğim hızlı bir korsanlık. Çalışır ve Boyer-Moore olmasa da oldukça yakın. Umarım yardım eder;)
public static final int BUFFER_SIZE = 32;
public static int [] buildShiftArray(byte [] byteSequence){
int [] shifts = new int[byteSequence.length];
int [] ret;
int shiftCount = 0;
byte end = byteSequence[byteSequence.length-1];
int index = byteSequence.length-1;
int shift = 1;
while(--index >= 0){
if(byteSequence[index] == end){
shifts[shiftCount++] = shift;
shift = 1;
} else {
shift++;
}
}
ret = new int[shiftCount];
for(int i = 0;i < shiftCount;i++){
ret[i] = shifts[i];
}
return ret;
}
public static byte [] flushBuffer(byte [] buffer, int keepSize){
byte [] newBuffer = new byte[buffer.length];
for(int i = 0;i < keepSize;i++){
newBuffer[i] = buffer[buffer.length - keepSize + i];
}
return newBuffer;
}
public static int findBytes(byte [] haystack, int haystackSize, byte [] needle, int [] shiftArray){
int index = needle.length;
int searchIndex, needleIndex, currentShiftIndex = 0, shift;
boolean shiftFlag = false;
index = needle.length;
while(true){
needleIndex = needle.length-1;
while(true){
if(index >= haystackSize)
return -1;
if(haystack[index] == needle[needleIndex])
break;
index++;
}
searchIndex = index;
needleIndex = needle.length-1;
while(needleIndex >= 0 && haystack[searchIndex] == needle[needleIndex]){
searchIndex--;
needleIndex--;
}
if(needleIndex < 0)
return index-needle.length+1;
if(shiftFlag){
shiftFlag = false;
index += shiftArray[0];
currentShiftIndex = 1;
} else if(currentShiftIndex >= shiftArray.length){
shiftFlag = true;
index++;
} else{
index += shiftArray[currentShiftIndex++];
}
}
}
public static int findBytes(InputStream stream, byte [] needle){
byte [] buffer = new byte[BUFFER_SIZE];
int [] shiftArray = buildShiftArray(needle);
int bufferSize, initBufferSize;
int offset = 0, init = needle.length;
int val;
try{
while(true){
bufferSize = stream.read(buffer, needle.length-init, buffer.length-needle.length+init);
if(bufferSize == -1)
return -1;
if((val = findBytes(buffer, bufferSize+needle.length-init, needle, shiftArray)) != -1)
return val+offset;
buffer = flushBuffer(buffer, needle.length);
offset += bufferSize-init;
init = 0;
}
} catch (IOException e){
e.printStackTrace();
}
return -1;
}
en basit olmayabilir, ancak oldukça hızlıdır. Bir akıştan okumakla ilgili kısıtlamaların, hız istediğinizde basit olmasına izin vermediğini düşünün.ama umarım benim kodum bazı sıkıntılarınızı hafifletebilir veya gelecekte birisine yardım edebilir. – dharga
Bit eski soru, ama işte benim cevabım. Okuma bloklarını buldum ve daha sonra arama yapmak, bir kerede sadece bir tane okumakla ve oradan gitmekle kıyaslandığında son derece verimsiz.
Ayrıca, IIRC, dizinin bir kısmı bir blok okumada ve yarısında bir diğerinde - ex, 12345'te 23'ü ararken 12, okuyamayacak, sonra okuyacak 34, kabul edilmez. maç, vs ... denemedim, net 4.0 gerektirdiği gibi. Her halükarda, bu daha basit ve daha hızlıdır.
static long ReadOneSrch(Stream haystack, byte[] needle)
{
int b;
long i = 0;
while ((b = haystack.ReadByte()) != -1)
{
if (b == needle[i++])
{
if (i == needle.Length)
return haystack.Position - needle.Length;
}
else
i = b == needle[0] ? 1 : 0;
}
return -1;
}
kodunuz yanlış. haystack = [2,1,2,1,1], needle = [2,1,1]. Kodunuz -1 döndürür, ancak doğru cevap 2'dir. – imaximchuk
Bunu kendim yapmalıydım, daha önce başlamıştım ve yukarıdaki çözümleri beğenmedim. Özellikle arama-bayt dizisinin nerede bittiğini bulmam gerekiyordu. Benim durumumda, akışı bayt dizisinden sonraya kadar ileri sarmalıyım. Eğer aradığınızı ...
İştevar afterSequence = stream.ScanUntilFound(byteSequence);
var beforeSequence = afterSequence - byteSequence.Length;
StreamExtensions.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace System
{
static class StreamExtensions
{
/// <summary>
/// Advances the supplied stream until the given searchBytes are found, without advancing too far (consuming any bytes from the stream after the searchBytes are found).
/// Regarding efficiency, if the stream is network or file, then MEMORY/CPU optimisations will be of little consequence here.
/// </summary>
/// <param name="stream">The stream to search in</param>
/// <param name="searchBytes">The byte sequence to search for</param>
/// <returns></returns>
public static int ScanUntilFound(this Stream stream, byte[] searchBytes)
{
// For this class code comments, a common example is assumed:
// searchBytes are {1,2,3,4} or 1234 for short
// # means value that is outside of search byte sequence
byte[] streamBuffer = new byte[searchBytes.Length];
int nextRead = searchBytes.Length;
int totalScannedBytes = 0;
while (true)
{
FillBuffer(stream, streamBuffer, nextRead);
totalScannedBytes += nextRead; //this is only used for final reporting of where it was found in the stream
if (ArraysMatch(searchBytes, streamBuffer, 0))
return totalScannedBytes; //found it
nextRead = FindPartialMatch(searchBytes, streamBuffer);
}
}
/// <summary>
/// Check all offsets, for partial match.
/// </summary>
/// <param name="searchBytes"></param>
/// <param name="streamBuffer"></param>
/// <returns>The amount of bytes which need to be read in, next round</returns>
static int FindPartialMatch(byte[] searchBytes, byte[] streamBuffer)
{
// 1234 = 0 - found it. this special case is already catered directly in ScanUntilFound
// #123 = 1 - partially matched, only missing 1 value
// ##12 = 2 - partially matched, only missing 2 values
// ###1 = 3 - partially matched, only missing 3 values
// #### = 4 - not matched at all
for (int i = 1; i < searchBytes.Length; i++)
{
if (ArraysMatch(searchBytes, streamBuffer, i))
{
// EG. Searching for 1234, have #123 in the streamBuffer, and [i] is 1
// Output: 123#, where # will be read using FillBuffer next.
Array.Copy(streamBuffer, i, streamBuffer, 0, searchBytes.Length - i);
return i; //if an offset of [i], makes a match then only [i] bytes need to be read from the stream to check if there's a match
}
}
return 4;
}
/// <summary>
/// Reads bytes from the stream, making sure the requested amount of bytes are read (streams don't always fulfill the full request first time)
/// </summary>
/// <param name="stream">The stream to read from</param>
/// <param name="streamBuffer">The buffer to read into</param>
/// <param name="bytesNeeded">How many bytes are needed. If less than the full size of the buffer, it fills the tail end of the streamBuffer</param>
static void FillBuffer(Stream stream, byte[] streamBuffer, int bytesNeeded)
{
// EG1. [123#] - bytesNeeded is 1, when the streamBuffer contains first three matching values, but now we need to read in the next value at the end
// EG2. [####] - bytesNeeded is 4
var bytesAlreadyRead = streamBuffer.Length - bytesNeeded; //invert
while (bytesAlreadyRead < streamBuffer.Length)
{
bytesAlreadyRead += stream.Read(streamBuffer, bytesAlreadyRead, streamBuffer.Length - bytesAlreadyRead);
}
}
/// <summary>
/// Checks if arrays match exactly, or with offset.
/// </summary>
/// <param name="searchBytes">Bytes to search for. Eg. [1234]</param>
/// <param name="streamBuffer">Buffer to match in. Eg. [#123] </param>
/// <param name="startAt">When this is zero, all bytes are checked. Eg. If this value 1, and it matches, this means the next byte in the stream to read may mean a match</param>
/// <returns></returns>
static bool ArraysMatch(byte[] searchBytes, byte[] streamBuffer, int startAt)
{
for (int i = 0; i < searchBytes.Length - startAt; i++)
{
if (searchBytes[i] != streamBuffer[i + startAt])
return false;
}
return true;
}
}
}
- 1. iyi yolu
- 2. iyi yolu
- 3. iyi yolu
- 4. iyi yolu
- 5. Jmeter'da en iyi yolu bulmanın en iyi yolu nedir?
- 6. iyi yolu html metni
- 7. iyi yolu şeyler
- 8. en iyi yolu?
- 9. en iyi yolu
- 10. iyi yolu MySQL
- 11. en iyi yolu
- 12. iyi yolu aynı tabloda
- 13. iyi yolu Ruby gibi
- 14. Linq'e katılmanın en iyi yolu
- 15. iyi yolu, Bildiğim kadarıyla HyperV
- 16. Bunu yazmanın daha iyi yolu?
- 17. Spree'yi özelleştirmenin en iyi yolu?
- 18. Kendi GPG/PGP parolanızı güçlendirmek için en iyi yolu kullanmanın en iyi yolu nedir?
- 19. Hata iletilerini işlemenin en iyi yolu
- 20. Node.js ile MongoDB'yi kullanmanın en iyi yolu?
- 21. ServiceManager'ı Model Sınıfında kullanmanın en iyi yolu?
- 22. Apache günlük dosyalarını döndürmenin en iyi yolu
- 23. Dikdörtgen nesneyi ayırmanın en iyi yolu
- 24. core.clj'yi kurmanın en iyi yolu nedir?
- 25. Selenyum webdriver üzerinde StaleElementReferenceException en iyi yolu
- 26. Git erişiminin en iyi yolu Git
- 27. Yapısal Mülkiyet veya daha iyi bir yolu?
- 28. Bu CSS'yi yazmanın daha iyi bir yolu?
- 29. Node.js'de daha iyi regex uygulaması yolu
- 30. Dosyayı sunucudan indirmenin en iyi yolu nedir
soru kafa karıştırıcı olduğunu: Ama sen de bu soru için benim çözüm kullanabilir? Akıştaki belirli bayt dizisi? – dharga
Sanırım sorunun başlığı güncellenmeli. Stream, Vana olarak etiketlenmesi gereken bir soru gibi görünmesini sağlayan Steam olarak yanlış yazılmış. – chollida
@chollida: Aslında, bunu düzeltmek için bu soruya geldim. – Powerlord