Entwickler-Ecke

Dateizugriff - Zusammen gesetzter Dateiname


norics - Mo 29.11.10 14:18
Titel: Zusammen gesetzter Dateiname
Hallo Zusammen,

ich möchte mir gerne meinen Dateinamen aus verschiedenen Kriterien zusammen bauen. In meinem Fall ist es der UserName und eine Auswahl aus der Listbox. Es wird nur der GetUser angezeigt. Wenn ich den GetUser weglasse, wird der Rest korrekt übernommen. Beides zusammen geht nicht.

(GetUser+'_'+IntToStr(ds[listbox1.itemindex+1].lfdnr)+'.txt');

Hat jemand eine Idee?

Viele Grüsse


bummi - Mo 29.11.10 14:31

was ist ds[ ??
setz mal einen Brechpunkt hier und steppe mit F7 rein...


norics - Mo 29.11.10 14:52

Hallo,

das ist ein Datensatz Array mit der lfdnr des ausgewählten Satzes.

Den kann ich auch weglassen und direkt die Auswahlnummer übernehmen.

Showmessage(GetUser+'_'+IntToStr(listbox1.itemindex+1)+'.txt');

Das geht aber auch nicht.

Gruss


Xion - Mo 29.11.10 14:58

user profile iconnorics hat folgendes geschrieben Zum zitierten Posting springen:
Das geht aber auch nicht.

Kannst du das präzisieren? WANN geht WAS nicht.

Die Zeile Code ist syntaktisch richtig würd ich sagen, der Compiler dürfte sich wohl nicht beschweren.

Gebe mal beides einzeln aus. Was zeigt er dann an? Was zeigt er jetzt an? Gib mal den genauen String hier an.


norics - Mo 29.11.10 15:48

Hallo,

hilfsweise lass ich mir das in der Messagebox anzeigen.

showmessage(IntToStr(ds[listbox1.itemindex+1].lfdnr)+'.txt'); Ergebnis => 3.txt
showmessage(GetUser); Ergebnis => meyer

showmessage(GetUser+'_'+IntToStr(listbox1.itemindex+1)+'.txt'); sollte eigentlich ergeben => meyer3.txt ; Ergebnis ist aber => meyer

Gruss


MaxWurzel - Mo 29.11.10 15:58

user profile iconnorics hat folgendes geschrieben Zum zitierten Posting springen:
sollte eigentlich ergeben => meyer3.txt

Sollte es nicht meyer_3.txt ergeben?

Edit: Was passiert, wenn du den String mit concat zusammensetzt?


Martok - Mo 29.11.10 16:18

Lass mich raten: GetUser gibt als letztes Zeichen ein #0 aus?

user profile iconMaxWurzel hat folgendes geschrieben Zum zitierten Posting springen:
Edit: Was passiert, wenn du den String mit concat zusammensetzt?
Das Gleiche, AFAIR wird exakt der gleiche Code generiert.


Xion - Mo 29.11.10 16:24

MSDN - GetUserName [http://msdn.microsoft.com/en-us/library/ms724432%28VS.85%29.aspx] hat folgendes geschrieben:
If the function succeeds, the return value is a nonzero value, and the variable pointed to by lpnSize contains the number of TCHARs copied to the buffer specified by lpBuffer, including the terminating null character.


Ok, die Frage ist ob GetUser diese Funktion verwendet...sehr wahrscheinlich ;)


bummi - Mo 29.11.10 16:36

kleb mal das Drum

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
Function RemoveZeros(s:AnsiString):AnsiString;
var
  i:Integer;
begin
  Result := '';
  for I := 1 to Length(s) do
    if s[i] <> #0 then Result := Result + s[i] ;
end;


jaenicke - Mo 29.11.10 16:46

Besser wäre es aber den Fehler (Nullzeichen ist zu viel in GetUser) zu beheben statt des Symptoms...


bummi - Mo 29.11.10 16:52

@jaenicke

stimmt, war auch nur zum testen gedacht....


norics - Mo 29.11.10 17:43

Moin Moin,

Tschuldigung . Klar sollte das "meyer_2.txt" dann sein.

Ich habe mir jetzt ganz unelegant mit einem edit Feld geholfen. Wenn ich das nacheinander einstelle (erst LoginUser dann den rest)kann ich das weiterverwenden.

Wenn jemand noch eine "schönere" Lösung anbieten kann, bitte gerne mitteilen.

Vielen Dank

Gruss


jaenicke - Mo 29.11.10 17:57

Naja, wie schon geschrieben wurde einfach deine GetUser Funktion korrigieren... die nimmt das Nullzeichen mit.


norics - Mo 29.11.10 18:11

Hallo Sebastian,

ich habe die Funktion so verändert. Das Ergebnis bleibt aber das gleiche.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function TForm1.GetUser: String;
 var CompName : Array [1..20of Char;
     SizeD : DWord;
     i:Integer;
 begin
 SizeD := 15;
 GetUserName( @CompName, SizeD );
   begin
   Result := '';
   for I := 1 to Length(CompName) do
     if CompName[i] <> #0 then Result := Result + CompName[i] ;
   end;
 result:=CompName;
 end;


Gruss
Volker

Moderiert von user profile iconMartok: Delphi-Tags gesetzt


Martok - Mo 29.11.10 18:13

Hallo!

Bitte verwende für Quellcode die entsprechenden [delphi]-Tags, dann wird er "schöner" dargestellt als im Fließtext. Beispiel:

Quelltext
1:
<span class="inlineSyntax"><span class="codecomment">{PROTECTTAG737bab35cb28800232285f888abd5c60}</span></span>                    

Wird:

Delphi-Quelltext
1:
var Test: integer;                    


Ich hab das gleich mal für dich erledigt, für die Zukunft dann.

Viele Grüße,
Martok


Gerd Kayser - Mo 29.11.10 18:22

user profile iconnorics hat folgendes geschrieben Zum zitierten Posting springen:
Beides zusammen geht nicht.

Probiere das einmal:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
var
  Dateiname : string;
...
  Dateiname := GetUser;
  Dateiname := Dateiname + '_' + IntToStr(ds[listbox1.itemindex + 1].lfdnr) + '.txt');
  ShowMessage(Dateiname);

Edit 1: ShowMessage nachgetragen


norics - Mo 29.11.10 18:34

Hallo Gerd,

Danke für den Vorschlag, das ist aber das gleiche Ergebnis wie vorher. Da ändert sich nichts.

Gruss
Volker


Delete - Mo 29.11.10 18:40

Lass die GetUser Funktion, wie sie ist und rufe am Ende nur Trim auf.


Gerd Kayser - Mo 29.11.10 18:56

Hier eine gerade getestete Version. Allerdings weiß ich nicht, was GetUser für eine Funktion ist. Im Beispiel habe ich es durch GetUserName ersetzt.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TForm1.Button1Click(Sender: TObject);
var
  Dateiname : string;
  Buffer    : array [0..32of char;  // ggf. vergrößern
  Groesse   : DWord;
begin
  Groesse := SizeOf(Buffer);
  GetUserName(Buffer, Groesse);
  Dateiname := Buffer + '_' + IntToStr(ListBox1.ItemIndex + 1) + '.txt';
  ShowMessage(Dateiname);
end;


norics - Mo 29.11.10 19:07

Hallo Gerd,

Vielen Dank. Komisch, das funktioniert. Ich sehe noch nicht wo der Unterschied liegt, aber ich werde den Sourcecode morgen mal aufräumen und das dann mal nachvollziehen.

Danke auch an die anderen.

Gruss
Volker


jaenicke - Mo 29.11.10 21:37

user profile iconnorics hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function TForm1.GetUser: String;
 var CompName : Array [1..20of Char;
     SizeD : DWord;
     i:Integer;
 begin
 SizeD := 15;
 GetUserName( @CompName, SizeD );
   begin
   Result := '';
   for I := 1 to Length(CompName) do
     if CompName[i] <> #0 then Result := Result + CompName[i] ;
   end;
 result:=CompName;
 end;
:autsch:
Da kannst du dir die Schleife auch komplett sparen...
Außerdem ist Length(CompName) durch das feste Array eh immer gleich. Warum du ein Array der Länge 20 definierst und dann als Größe 15 übergibst, ist mir allerdings ein Rätsel.

Außerdem ist die maximale Länge UNLEN als 255 oder so definiert...

Jedenfalls schau dir doch bitte einmal die Dokumentation an... Du bekommst die Anzahl der Zeichen schließlich auf dem Silbertablett.


Delete - Mo 29.11.10 21:51

Ein feste Buffergröße festzulegen ist schlecht. Du sagst ja selber, dass du nicht weißt, wie groß er sein muss.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
function GetCurrUserName: string;
var
  Size              : DWORD;
begin
  Size := MAX_COMPUTERNAME_LENGTH + 1;
  SetLength(Result, Size);
  if GetUserName(PChar(Result), Size) then
    SetLength(Result, Size)
  else
    Result := '';
end;

Und am Ende gegeben falls noch Trim aufrufen um unnötige Steuerzeichen zu entfernen.


jaenicke - Mo 29.11.10 21:54

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
2:
  if GetUserName(PChar(Result), Size) then
    SetLength(Result, Size)
Nicht ganz, da bist du auf genau das reingefallen, was glaube ich du mal in der DP gepostet hattest. ;-)
Dass nämlich beim Computernamen in der Größenangabe das Nullzeichen nicht dabei ist, hier aber schon. Also:

Delphi-Quelltext
1:
SetLength(Result, Size - 1)                    
;-)
Und dann kann man sich das Trim auch sparen.


Delete - Mo 29.11.10 22:05

Hm, dann muss ich meine Funktion in meinem Archiv mal überprüfen.


delphi10 - Mo 29.11.10 23:20

user profile iconnorics hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Zusammen,

ich möchte mir gerne meinen Dateinamen aus verschiedenen Kriterien zusammen bauen. In meinem Fall ist es der UserName und eine Auswahl aus der Listbox. Es wird nur der GetUser angezeigt. Wenn ich den GetUser weglasse, wird der Rest korrekt übernommen. Beides zusammen geht nicht.

(GetUser+'_'+IntToStr(ds[listbox1.itemindex+1].lfdnr)+'.txt');

Hat jemand eine Idee?

Viele Grüsse


Versuch das mal:

Delphi-Quelltext
1:
2:
3:
4:
5:
// Result enthält den Usernamen + #0
// also Result := GetUser;
If Result[length(Result)+1] = #0 then
 Result := copy(Result,1,length(Result)-1);
 Showmessage(Result+'_'+IntToStr(ds[listbox1.itemindex+1].lfdnr)+'.txt');

Gruß delphi10


Delete - Mo 29.11.10 23:28

Ihr macht mich noch wahnsinnig. Warum versucht ihr krampfhaft Trim nicht zu verwenden, sondern entwickelt andauernd eure eigenen frickel Lösungen?


jaenicke - Di 30.11.10 00:16

user profile icondelphi10 hat folgendes geschrieben Zum zitierten Posting springen:
// Result enthält den Usernamen + #0
Aber auch nur, wenn man die API-Funktion falsch benutzt. :roll:
Siehe oben...

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Warum versucht ihr krampfhaft Trim nicht zu verwenden, sondern entwickelt andauernd eure eigenen frickel Lösungen?
Im Nachhinein Trim zu verwenden, weil man die Funktion falsch aufruft, ist aber auch nicht gerade sauber.

Deshalb hier einmal die laut Dokumentation korrekte Variante:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function GetCurrUserName: string;
const
  UNLEN = 256;
var
  BufferSize: DWORD;
begin
  BufferSize := UNLEN + 1;
  SetLength(Result, BufferSize);
  if GetUserName(PChar(Result), BufferSize) then
    SetLength(Result, BufferSize - 1)
  else
    Result := '';
end;
Damit funktioniert es auch korrekt.

@user profile iconLuckie: MAX_COMPUTERNAME_LENGTH ist die falsche Konstante. Benutzernamen können durchaus länger als 15 Zeichen sein. UNLEN als Maximallänge ist in der API als 256 definiert.


Delete - Di 30.11.10 00:25

Ächtz, langsam wird es peinlich. Ist irgendwo ein Schreibtisch in der Nähe zum darunter Kriechen? :roll:


delphi10 - Di 30.11.10 00:39

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
user profile icondelphi10 hat folgendes geschrieben Zum zitierten Posting springen:
// Result enthält den Usernamen + #0
Aber auch nur, wenn man die API-Funktion falsch benutzt. :roll:
Siehe oben...
Deshalb hier einmal die laut Dokumentation korrekte Variante:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function GetCurrUserName: string;
const
  UNLEN = 256;
var
  BufferSize: DWORD;
begin
  BufferSize := UNLEN + 1;
  SetLength(Result, BufferSize);
  if GetUserName(PChar(Result), BufferSize) then
    SetLength(Result, BufferSize - 1)
  else
    Result := '';
end;
Damit funktioniert es auch korrekt.

Wieso falsch benutzt? Die API kann man nur so aufrufen, wie du es beschrieben hast. Das Ergebnis muss, will man die null weghaben, immer nachbehandelt werden. Deine Version ist allerdings eleganter.


Delete - Di 30.11.10 02:08

OK, hier ist die korrigierte Funktion:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
function GetCurrentUserName: string;
const
  UNLEN = 256;
var
  Size              : DWORD;
begin
  Size := UNLEN + 1;
  SetLength(Result, Size);
  if GetUserName(PChar(Result), Size) then
    SetLength(Result, Size - 1)
  else
    raise Exception.Create(SysErrorMessage(GetLastError));
end;


Gerd Kayser - Di 30.11.10 09:46

user profile iconnorics hat folgendes geschrieben Zum zitierten Posting springen:
Ich sehe noch nicht wo der Unterschied liegt
So gehts auch:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
function TForm1.GetUser: string;
var
  Buffer  : array [0..256of char;
  Groesse : DWord;
begin
  Groesse := SizeOf(Buffer);
  GetUserName(Buffer, Groesse);
  Result := Buffer;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(GetUser + '_' + IntToStr(ListBox1.ItemIndex + 1) + '.txt');
end;


Delete - Di 30.11.10 12:32

Der Unterschied liegt darin, dass ich das Ergebnis auf die tatsächliche Größe zu recht stutze und so verhindere, dass noch Müll mit ausgeliefert wird. Außerdem habe ich einer Fehlerbehandlung, die eine Exception wirft, wenn was schief geht. Bei dir würde einfach Müll zurückgegeben.


Gerd Kayser - Di 30.11.10 18:05

user profile iconLuckie hat folgendes geschrieben Zum zitierten Posting springen:
Der Unterschied liegt darin, dass ich das Ergebnis auf die tatsächliche Größe zu recht stutze und so verhindere, dass noch Müll mit ausgeliefert wird. Außerdem habe ich einer Fehlerbehandlung, die eine Exception wirft, wenn was schief geht. Bei dir würde einfach Müll zurückgegeben.
Da liegst Du aber falsch.
1. Durch "Result := Buffer;" werden nur die relevanten Bytes ohne #0 übertragen.
2. Das Array of Char hat als erstes Zeichen ein #0. Wird GetUserName z. B. mit Groesse = 3 aufgerufen, obwohl der Name länger ist, dann bleibt das Array mit der #0 als erstem Zeichen unverändert. Nur der Wert der Variablen Groesse ändert sich. Result ist dann ein LeerString, enthält also auch in diesem Fall keinen Müll.
3. Wenn der Buffer 256 Bytes groß sein soll (siehe UNLEN), das Array auch mindestens so groß ist (in meinem Beispiel 257 Bytes), die Groesse richtig an die Funktion übermittelt wird, was soll dann schief gehen? Wenn trotz richtigem Aufruf etwas dennoch schief laufen sollte, hat der Anwender wohl ein größeres Problem, das aber nicht an der Anwendung liegt, sondern wohl eher an Windows. Man kann sich auch zu Tode prüfen.


bummi - Di 30.11.10 18:21

da bin ich froh daß meine 10 Jahre alte Funktion bis XE durchgehalten hat.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Function Get_UserName:String;
var
  p:Pchar;
  dw:Dword;
begin
  dw:=255;
  p:=stralloc(dw);
  GetUsername(p,dw);
  Result:=StrPas(p);
  strdispose(p);
end;