Solved

streams

Posted on 2002-06-22
16
403 Views
Last Modified: 2010-04-04
i need to be able to add together 'x' streams into one stream and then take all the seporate the one stream back into 'x' streams.
plz help asap!
0
Comment
Question by:mgazza
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 9
  • 4
  • 3
16 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 7101003
a sample from my paq,

splitting and concanating back any file by using any fragment size

unit splitfiles_u;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
  Button1: TButton;
  OpenDialog1: TOpenDialog;
  Edit1: TEdit;
  SaveDialog1: TSaveDialog;
  Button2: TButton;
  Label1: TLabel;
  procedure Button1Click(Sender: TObject);
  procedure Button2Click(Sender: TObject);
private
  { Private declarations }
public
  { Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

//Splitting Files
procedure TForm1.Button1Click(Sender: TObject);
var
i, WantedFragSize, RealToWrite : Integer;
InStream, OutStream : TFileStream;
S : String;
begin
if Opendialog1.Execute then
begin
  SaveDialog1.Title := 'Select Dir and input FilePrefix without Suffix';
  If SaveDialog1.Execute then
  begin
    WantedFragSize := StrtoInt(Edit1.Text);  //Wanted SplitSize
    i := 0;
    InStream  := TFileStream.Create(OpenDialog1.FileName,fmOpenRead);
    try
      while (InStream.Position < InStream.Size) do
      Begin
        s := IntToStr(I);                   //Building numeric suffix
        while Length(s) < 3 do s := '0'+s;
        s := '.'+s;
        If InStream.Size - InStream.Position < WantedFragSize then
          RealToWrite := InStream.Size - InStream.Position
        else
          RealToWrite := WantedFragSize;
        OutStream  := TFileStream.Create(SaveDialog1.FileName+s,fmCreate);
        try
          OutStream.CopyFrom(InStream,RealToWrite);
          Inc(i);
        finally
          OutStream.Free;
        end;
      end;
    Finally
      InStream.Free;
    end;
  end;
end;
end;

//concanating files
procedure TForm1.Button2Click(Sender: TObject);
var
i : Integer;
InStream, OutStream : TFileStream;
SourcePath, FragName, S : String;
begin
Opendialog1.Title := 'Select any Fragmented File';
if Opendialog1.Execute then
begin
  SourcePath := ExtractFilePath(Opendialog1.FileName);
  FragName := ExtractFileName(Opendialog1.FileName);
  SaveDialog1.Title := 'Select Dir and input the FileName with Suffix';
  If SaveDialog1.Execute then
  begin
    i := 0;
    s := IntToStr(I);
    while Length(s) < 3 do s := '0'+s;
    s := '.'+s;
    FragName := ChangeFileExt(FragName, s);
    If FileExists(SourcePath+FragName) then
    begin
      OutStream := TFileStream.Create(Savedialog1.FileName,fmCreate);
      try
        While FileExists(SourcePath+FragName) do
        Begin
          InStream  := TFileStream.Create(SourcePath+FragName,fmOpenRead);
          try
            OutStream.CopyFrom(InStream,0);
            Inc(i);
            s := IntToStr(I);
            while Length(s) < 3 do s := '0'+s;
            s := '.'+s;
            FragName := ChangeFileExt(FragName, s);
          finally
            InStream.Free;
          end;
        end;
      finally
        OutStream.Free;
      end;
    end;
  end;
end;
end;

end.

meikl ;-)
0
 
LVL 1

Author Comment

by:mgazza
ID: 7101091
nice fancy bit of coding iv been trying to do something like tha 4 ages can't try it now int 1:00 am i will try it in the moring well when its light thanks ne way
0
 
LVL 1

Author Comment

by:mgazza
ID: 7101385
sos i dont know how to use it
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 27

Expert Comment

by:kretzschmar
ID: 7101408
splitfiles
-just type a number in the edit = fragmentsize in bytes
-press button1->select a file->file is splitted now->splitted files have as name filename.numbercount

concanating files
-select one splitted file
-give the desination filename->splitted files are concanted to the given filename

just tell me, where you have a problem,
if needed i can send you the compiled project
(leave your mail-adress here, in this case)

meikl ;-)
0
 
LVL 1

Author Comment

by:mgazza
ID: 7101435
this adds togeterth all the files into one file what i need now is something that searches for [newfile] and writes it out to a nother stream this works fine for the first file but when writing the second file it writes the first file in it heres the bit of code for adding the files together(this part works fine);

procedure TForm1.Button1Click(Sender: TObject);
var
ins,outs:tmemorystream;
i:integer;
temp:tstringlist;
begin
temp:=tstringlist.Create;
ins:=tmemorystream.Create;
outs:=tmemorystream.Create;
temp.Text:='[newfile]';
for i:=0 to strtoint(edit1.text)-1 do
begin
opendialog1.Execute;
ins.LoadFromFile(opendialog1.FileName);
ins.SaveToStream(outs);
temp.SaveToStream(outs);
end;
savedialog1.Execute;
outs.SaveToFile(savedialog1.FileName);
end;

0
 
LVL 1

Author Comment

by:mgazza
ID: 7101438
this adds togeterth all the files into one file what i need now is something that searches for [newfile] and writes it out to a nother stream this works fine for the first file but when writing the second file it writes the first file in it heres the bit of code for adding the files together(this part works fine);

procedure TForm1.Button1Click(Sender: TObject);
var
ins,outs:tmemorystream;
i:integer;
temp:tstringlist;
begin
temp:=tstringlist.Create;
ins:=tmemorystream.Create;
outs:=tmemorystream.Create;
temp.Text:='[newfile]';
for i:=0 to strtoint(edit1.text)-1 do
begin
opendialog1.Execute;
ins.LoadFromFile(opendialog1.FileName);
ins.SaveToStream(outs);
temp.SaveToStream(outs);
end;
savedialog1.Execute;
outs.SaveToFile(savedialog1.FileName);
end;

0
 
LVL 1

Author Comment

by:mgazza
ID: 7101445
this adds togeterth all the files into one file what i need now is something that searches for [newfile] and writes it out to a nother stream this works fine for the first file but when writing the second file it writes the first file in it heres the bit of code for adding the files together(this part works fine);

procedure TForm1.Button1Click(Sender: TObject);
var
ins,outs:tmemorystream;
i:integer;
temp:tstringlist;
begin
temp:=tstringlist.Create;
ins:=tmemorystream.Create;
outs:=tmemorystream.Create;
temp.Text:='[newfile]';
for i:=0 to strtoint(edit1.text)-1 do
begin
opendialog1.Execute;
ins.LoadFromFile(opendialog1.FileName);
ins.SaveToStream(outs);
temp.SaveToStream(outs);
end;
savedialog1.Execute;
outs.SaveToFile(savedialog1.FileName);
end;

0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 7102783
well, could you tell me, what you want to do?
0
 
LVL 2

Expert Comment

by:mikepj
ID: 7123772
I needed to do this recently.  Effectively this is what I did; more detailed example available.

You'd need to save it with the size info something like this:

var
  iBytes:cardinal;
begin
  iPart1Bytes:=strm1.Size;
  strmOut.WriteBuffer(iBytes,sizeof(iBytes));

  iPart2Bytes:=strm2.Size;
  strmOut.WriteBuffer(iBytes,sizeof(iBytes));

  strmOut.CopyFrom(strm1,strm1.Size);
  strmOut.CopyFrom(strm2,strm2.Size);
  ....
end;

To get your data out, you'd need to do something like:

var
  iBytes:cardinal;
begin
  strmIn.ReadBuffer(iBytes,sizeof(iBytes));
  strm1.CopyFrom(strmIn,iBytes);

  strmIn.ReadBuffer(iBytes,sizeof(iBytes));
  strm2.CopyFrom(strmIn,iBytes);
  ...
end;
0
 
LVL 2

Expert Comment

by:mikepj
ID: 7123844
Oops; I mixed up the answer.  Here it is again

var
 iBytes:cardinal;
begin
 ...
 iBytes:=strm1.Size;
 strmOut.WriteBuffer(iBytes,sizeof(iBytes));
 strmOut.CopyFrom(strm1,strm1.Size);

 iBytes:=strm2.Size;
 strmOut.WriteBuffer(iBytes,sizeof(iBytes));
 strmOut.CopyFrom(strm2,strm2.Size);
 ...
end;

To get your data out, you'd need to do something like:

var
 iBytes:cardinal;
begin
 ...
 strmIn.ReadBuffer(iBytes,sizeof(iBytes));
 strm1.CopyFrom(strmIn,iBytes);

 strmIn.ReadBuffer(iBytes,sizeof(iBytes));
 strm2.CopyFrom(strmIn,iBytes);
 ...
end;
0
 
LVL 1

Author Comment

by:mgazza
ID: 7140122
sorry! iv been on my hols !sorry 4 no replying!
0
 
LVL 1

Author Comment

by:mgazza
ID: 7140127
here is i bit iv been working on but it dont work

procedure TForm1.Button1Click(Sender: TObject);
var
s1,s2,s3:tstringlist;
strem1:tmemorystream;
i,ii,iii,del:integer;
begin
strem1:=tmemorystream.Create;
s1:=tstringlist.Create;
s2:=tstringlist.Create;
s3:=tstringlist.Create;

opendialog1.Execute;
strem1.LoadFromFile(opendialog1.FileName);
s1.LoadFromStream(strem1);
/////first
for i:=0 to s1.Count-1 do
begin
if s1.Strings[i]='[newfile]'  then
s2.AddObject(inttostr(random(400000)),tmemorystream.Create);
end;
///////next
for iii:=0 to s2.Count-1 do
begin
ii:=0;
while s1.Strings[ii]<>'[newfile]' do
begin
s3.Add(s1.Strings[ii]);
ii:=ii+1;
end;
//
for del:=0 to s3.Count-1 do
begin
s1.delete(del);
end;
//
savedialog1.Execute;
s3.SaveToStream(tmemorystream(s2.Objects[iii]));
tmemorystream(s2.Objects[iii]).SaveTofile(savedialog1.FileName);
s3.Clear;
tmemorystream(s2.Objects[iii]).free;

end;


end;

does your bit of code add files together and take them apart?
if so mail me the sorce code! rcmgazza2@hotmail.com!
thank you!!!
0
 
LVL 2

Expert Comment

by:mikepj
ID: 7140789
Yes; I put a string list and a binary file in the same file.  Essentially what I did is:

1) Write a 4 byte file content marker
2) Write the length of the string list as a string
3) Write the string list as a string
4) Write the length of the binary file
5) Write the binary file

Parts 2 and 3 are handled by the routine below
Part 4 I actually skipped because I didn't need it

To read it:

1) Read and check the 4 byte content marker
2) Read the length of the string list as a string
3) Read n bytes
4) Read the string list string
5) Read the length of the binary section
6) Read the binary section

Parts 2-4 are handled by the routine below.
Part 5 I actually skipped because I didn't need it

The TStringList.SaveToStream and LoadToStream methods aren't as good as you might expect...they pay no attention to the length of the string written.  I expanded my TStringList descendant as follows so that the size will always be written and considered upon read.

  TMyStringList = Class(TStringList)
    Published
      procedure SmartSaveToStream(strm:TStream);
      procedure SmartLoadFromStream(strm:TStream);
    End;

procedure TMyStringList.SmartSaveToStream(strm:TStream);
var
  iBytes:cardinal;
  s:string;
begin
  s:=Text;
  iBytes:=Length(s);
  strm.WriteBuffer(iBytes,sizeof(iBytes));
  strm.WriteBuffer(Pointer(S)^, Length(S));
end;

procedure TMyStringList.SmartLoadFromStream(strm:TStream);
var
  iBytes:cardinal;
  s:string;
begin
  strm.ReadBuffer(iBytes,sizeof(iBytes));
  SetLength(s,iBytes);
  strm.ReadBuffer(Pointer(S)^, Length(S));
  Text:=s;
end;

This code will allow you to blindly write as many stringlists to the stream and blindly read them back without needing to worry about the length.

If you need more, I could provide more info.

MP
0
 
LVL 1

Author Comment

by:mgazza
ID: 7140832
email me the full file adder  .pas .dfm ziped up thanks!;-)
0
 
LVL 1

Author Comment

by:mgazza
ID: 7141104
var
sizelog:tstringlist;
mainfile:tmemorystream;
{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
sizelog:=tstringlist.Create;
mainfile:=tmemorystream.Create;
end;
 //winzip drag drop
procedure TForm1.Button1Click(Sender: TObject);
var
nowfile:tmemorystream;
begin
nowfile:=tmemorystream.Create;
if opendialog1.Execute then
begin
nowfile.LoadFromFile(opendialog1.FileName);
sizelog.Add(inttostr(nowfile.size));
nowfile.SaveToStream(mainfile);
end;
end;
 //winzip close write
procedure TForm1.Button2Click(Sender: TObject);
var
thestrings:tmemorystream;
begin
thestrings:=tmemorystream.Create;
sizelog.SaveToStream(thestrings);
//double the strings size to the main filesize
thestrings.SetSize(mainfile.Size);
thestrings.SaveToStream(mainfile);

savedialog1.Execute;
mainfile.SaveToFile(savedialog1.FileName);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
files,strings:tmemorystream;
resetsizes:tstringlist;
begin
strings:=tmemorystream.Create;
files:=tmemorystream.Create;
resetsizes:=tstringlist.Create;

if opendialog1.Execute then
begin

/////continued
end;

here is a notherway of adding files and taking them apart!!
this one will work!!!
compile this and i will show you what it needs next!
///@ the continue
"files"  needs to read the first half of the file and
"strings" needs to read the second half of the file;
save "strings" to "resetsizes" and
then "files" needs to be splitup and each part saved into the sizes shown by each string in "resetsizes" !!!!;-)
0
 
LVL 2

Accepted Solution

by:
mikepj earned 75 total points
ID: 7142388
You've made the writing of the file as complex as possible and then hope I'll write the code for reading.  I don't see why you did many of the things you did in your last example.

For 60 points I don't write code.  There are MANY ways to accomplish what you want.  I have given you a nice simple solution that works.  

You presume that I would give you my DFM and PAS file showing the use of this but that comprises 1500 lines of code for many things.  Apart from my not wanting to release my code, it would cause more confusion and questions for you than it's worth.

Instead I've snipped out the "guts" of the stream append and split.  Use it only as an example.  Once you understand the example, adapt yours to do something similar.  The ZCompress/ZDecompress compresses the binary stream and adds it to the end of the text stream.  SmartSaveToStream and SmartLoadFromStream take care of the length tracking.

MP

// export

      strSrce:=TFileStream.Create(sTempFile,fmOpenRead+fmShareDenyNone);

      // protect against strSrce memory leak in case strDest fails
      try
        strDest:=TFileStream.Create(sDest,fmCreate);
      except
        strSrce.Free;
        raise;
      end;

      slExportInfo:=TMyStringList.Create;
      try  // finally
        // file ID marker
        strDest.Write(g_scMarker[1],Length(g_scMarker));

        slExportInfo.Values[g_scFileType]:=g_scExportTypeData;
        slExportInfo.Values[g_scExportTitle]:=edtTitle.Text;
        slExportInfo.SmartSaveToStream(strDest);

        // the rest of the stream is entirely zip content
        ZCompressStream(strSrce,strDest);
      finally
        strDest.Free;
        strSrce.Free;
        slExportInfo.Free;
      end;


// import

    strSrce:=TFileStream.Create(sFilename,fmOpenRead+fmShareDenyNone);

    // protect against strSrce memory leak in case strDest fails
    try
      strDest:=TFileStream.Create(sTempFile,fmCreate);
    except
      strSrce.Free;
      raise;
    end;

    slImportInfo:=TMyStringList.Create;
    try  // finally
      SetLength(sMarker,Length(g_scMarker));
      strSrce.Read(sMarker[1],Length(sMarker));

      if sMarker<>g_scMarker then
        Raise EUserProblem.CreateFmt('Import file "%s" is not suitable for '+g_sProgName,[sFilename]);

      slImportInfo.SmartLoadFromStream(strSrce);

      sFileType:=slImportInfo.Values[g_scFileType];

      if sFileType<>g_scExportTypeData then
        Raise EUserProblem.CreateFmt('File type %s is not suitable for '+g_sProgName,[sFileType]);

      // the rest of the stream is entirely zip content
      ZDecompressStream(strSrce,strDest);
    finally
      strSrce.Free;
      strDest.Free;
      slImportInfo.Free;
    end;

-end-
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

738 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question