problem z dodaniem stringów

0

witam,
sprawa wydaje się trywialna - w końcu zwykłe dodawanie stringów, ale jednak zatrzymało mnie na dość długo.. Dlatego prosiłbym o zerknięcie na kod:

 
var
  user  : string;
  dl : dword;
  a,b:string;

begin

  dl := 254;          //nazwa usera -> user
  SetLength(user, dl);
  GetUserName(PChar(user),dl);
  SetLength(user, dl);


  a:='C:\Users\'+user+'\AppData\';  //łączenie ścieszki
  a:=a+b;

 showMessage(a);

end;

program wyświetli jedynie ":\Users[nazwa usera]". Pytanie, dlaczego mi tak ucina, że nie jestem w stanie dodać czegokolwiek po zmiennej 'user' (w której zapisana jest nazwa aktualnego urzytkownika)? Niezależnie od wartości zmiennej b, efekt jest taki sam. Co mogę z tym zrobić?

Pozdrawiam
Kszk

1

Jak ci coś nie działa to zaczynaj czytać dokumentacje na temat wykorzystanych funkcji:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724432%28v=vs.85%29.aspx
... including the terminating null character. ...

SetLength(user,dl-1);

2

Dlaczaego nie użyjesz zmiennej środowiskowej %APPDATA% albo %LOCALAPPDATA%, albo funkcji WinAPI SHGetFolderPath z parametrem CSIDL_APPDATA?

Takie sklejanie stringa 'c:\users'+cośtam jest po prostu nieprawidłowe: na XP nie ma "Users" tylko "Documents and Settings", Windows wcale nie musi być na C:, ani nie przewidzisz jak foldery będą się nazywały w przyszłych wersjach systemu.

0

... including the terminating null character. ...

SetLength(user,dl-1);

pomogło, głupi błąd..

Takie sklejanie stringa 'c:\users'+cośtam jest po prostu nieprawidłowe: na XP nie ma "Users" tylko "Documents and Settings", Windows wcale nie musi być na C:, ani nie przewidzisz jak foldery będą się nazywały w przyszłych wersjach systemu

o tym nie pomyślałem. użycie appdate uprościło sprawę :)

ale teraz pytanie jak pójść dalej, czyli jak znaleźć plik i wydobyć ścieżkę do niego? Boduch pisał o funkcji findfirst, ale z tego co czytałem, ta funkcja nie zwraca ścieżki do danego pliku.

0

czytałem już to i z tego co zrozumiałem informacje nt znalezionego pliku to rozmiar, nazwa, atrybuty etc, ale nie ma ścieżki dostępu.

  • na podanym przykładzie:
    " Na podstawie zdobytej wiedzy można napisać prostą procedurę odnajdującą pliki w danym katalogu:"
    wywnioskowałem, że ta funkcja szuka tylko w danym katalogu, nie zagłębiając się w podkatalogi, tak?

czyli jedyna opcja to spróbować jakoś rekurencyjnie to zrobić, żeby zapamiętywał bieżącą ścieżkę, gdzie szuka. gdy znajdzie, skończy szukanie, a ostatnia zapisana ścieżka jest w moim wypadku ścieżką, którą szukam. dobrze rozumuje?

0

(...) wywnioskowałem, że ta funkcja szuka tylko w danym katalogu, nie zagłębiając się w podkatalogi, tak?

FindFirst działa w obrębie jednego katalogu, tak.

czyli jedyna opcja to spróbować jakoś rekurencyjnie to zrobić, żeby zapamiętywał bieżącą ścieżkę, gdzie szuka. gdy znajdzie, skończy szukanie, a ostatnia zapisana ścieżka jest w moim wypadku ścieżką, którą szukam. dobrze rozumuje?

Coś w tym guście (pisane z palca):

Var FoundFileList: TStringList;

Procedure SearchDir(const FileName, CurrentDir: String);
Var M: TSearchRec;
Begin
 CurrentDir := AddTrailingBackslash(CurrentDir);

 if (FindFirst(CurrentDir+'*.*', faAnyFile or faDirectory, M) = 0) Then
  Exit;
 
 Repeat
  if ((M.Attr and faDirectory) <> faDirectory) Then
   SearchDir(CurrentDir+M.Name) Else

  if (M.Name = FileName) Then
   FoundFileList.Add(CurrentDir+M.Name);
 Until (FindNext(M) <> 0);

 FindClose(M);
End;

initialization
 FoundFileList := TStringList.Create;

Wywołanie np.: SearchDir('myfile.txt', 'C:');

0

nie rozumiem dokładnie działania procedury. dokładniej 2 fragmenty:

if (FindFirst(CurrentDir+'*.*', faAnyFile or faDirectory, M) = 0) Then 

czy Directory nie zawiera się w AnyFile? wiec nie wystarczyłoby samo faAnyFile?

FoundFileList.Add(CurrentDir+M.Name); 

tutaj zapisujemy gotową ścieżkę do tej listy stringów. nie spotkałem sie nigdy z taką konstrukcją. to coś w stylu stosu? Nie mogę znaleźć nigdzie jak się za to zabrać, żeby odczytać dane z tej listy

0

Nie mogę znaleźć nigdzie jak się za to zabrać, żeby odczytać dane z tej listy

delphi TStringList nic nie zwraca?

FoundFileList.Count to ilość elementów na tej liście, a aby odczytać któryś z nich należy skorzystać z FoundFileList[ID] lub FoundFileList.Strings[ID] (iterowane od zera).
Np.:

For I := 0 To FoundFileList.Count-1 Do
 Writeln(FoundFileList[I]);

lub

Var Str: String;
{...}
For Str in FoundFileList Do
 ...
0

myślałem, że dalej sam sobie poradzę, ale jednak nie.. nie działa rekurencja, tzn znajduje mi plik tylko w katalogu głównym. Jeżeli go usunąć to nic nie znajduje

zmodyfikowałem trochę kod:

 
Procedure SearchDir(const FileName: string; CurrentDir: String);
Var M: TSearchRec;
Begin
  if CurrentDir[length(CurrentDir)] <> '\' then CurrentDir := CurrentDir + '\';

 if (FindFirst(CurrentDir+'*.*', faAnyFile or faDirectory, M) <> 0) Then
  Exit;

 Repeat

  if ((M.Attr and faDirectory) <> faDirectory) Then
   SearchDir(filename, CurrentDir+M.Name) Else;
  if (M.Name = FileName) Then begin
   FoundFileList.Add(CurrentDir+M.Name);
   end;
 Until (FindNext(M) <> 0);

 FindClose(M);
End;

wywołuje poprzez:

SearchDir('do.txt', 'C:'); 
1

Nieco podrasowana wersja:

Procedure SearchFile(FileName, CurrentDir: String);
Var SRec: TSearchRec;
Begin
 if (CurrentDir[Length(CurrentDir)] <> DirectorySeparator) Then
  CurrentDir += DirectorySeparator; // ew.`CurrentDir := CurrentDir+DirectorySeperator;` jeżeli piszesz w delfi...

 // 1) przeszukujemy wyłącznie pliki
 if (FindFirst(CurrentDir+'*.*', faAnyFile and (not faDirectory), SRec) <> 0) Then
  Exit;

 Repeat
  if (AnsiCompareFileName(SRec.Name, FileName) = 0) Then // jeżeli nazwy plików się zgadzają...
   FoundFileList.Add(CurrentDir+SRec.Name); // dodajemy do listy odnalezionych plików
 Until (FindNext(SRec) <> 0);
 FindClose(SRec);

 // 2) przeszukujemy wyłącznie katalogi
 if (FindFirst(CurrentDir+'*.*', faDirectory, SRec) <> 0) Then
  Exit;

 Repeat
  if (SRec.Name = '.') or (SRec.Name = '..') Then
   Continue;

  SearchFile(FileName, CurrentDir+SRec.Name); // szukamy w danym katalogu
 Until (FindNext(SRec) <> 0);
 FindClose(SRec);
End;

W pierwszej fazie szukania wyszukuje wyłącznie pliki, a w drugiej wchodzi po kolei do każdego katalogu - zasada działania jest prosta ;)
Jest to idealny przykład, gdzie wypadałoby zastosować wątki, ale to już sobie darowałem :P

0

lepiej :P wyszukuje mi poprawnie większość plików. jedynie jeżeli plik jest w katalogu ukrytym/systemowym np w tym co było mowa na początku: 'C:\Users[nazwa]'\AppData\ to już ich nie widzi. czy jest względnie prosta metoda, która sprawi, że będziesz szukać również w nich? :)

0

Powinno wyszukiwać również tam; może spróbuj uruchomić z prawami administratora?

0

już próbowałem tak, bez różnicy

1

faAnyFile - faDirectory
Serio, tak się maski bitowe odejmuje?
faAnyFile and (not faDirectory)

http://www.freepascal.org/docs-html/rtl/sysutils/findfirst.html
Ta dokumentacja wskazuje że faAnyFile nie zawiera maski faDirectory. Więc radzę budować maski bitowe poprawnie i dodać odpowiednie atrybuty których FPC nie musi stosować domyślnie...

0

Przypominam sobie, że stare wersje Delphi miały zwaloną wartość faAnyFile, co powoduje niewykrywanie niektórych plików na nowych systemach (Vista+).

spróbuj

faAnyFile or $80

to tajemnicze $80 to jest faNormal, nowy atrybut, nie uwzględniony przez faAnyFile w starszych Delphi.

0

w wielu przypadkach dodawanie i odejmowanie masek daje poprawny wynik, ale nie zawsze, dlatego z założenia należy używać operacji bitowych.

Dlaczego wyglądam na osobę która nie rozumie operacji dodawania i odejmowania liczb...? Ale rozumiem, dział newbie, więc nie zakładamy że osoby które tu zaglądają wiedzą jak działa odejmowanie...
Odejmowanie i dodawanie masek bitowych powoduje błędy i zaciemnia kod, gdyż masek się nie odejmuje ani nie dodaje. I @Patryk27 powinien za swój kod dostać po pupie zwłaszcza że to recydywa.

Przypominam sobie, że stare wersje Delphi miały zwaloną wartość faAnyFile, co powoduje niewykrywanie niektórych plików na nowych systemach (Vista+).

Typowe rozwiązanie: aktualizacja kompilatora. No ale my mówimy o Delphi, w szczególności 7 i już wiadomo że mówimy o uparciuchach którzy mają 10+letnie przyzwyczajenia...

0

wydaje mi się, że program nie wchodzi do ukrytych katalogów, a zmiany które proponujecie odnoszą się do przeszukiwania tylko plików w danym folderze.

przynajmniej takie mam odczucie po przeniesieniu pliku, który wcześniej był znajdywany do ukrytego katalogu - program nie znajdywał go

używam d7

0

Ja już od jakiegoś czasu nie korzystam z metod wyszukiwanie plików i katalogów dostępnym pod VCL. Zamiast tego korzystam z funkcji WinAPI do tego celu. W strukturze typu TWIN32FindDataA/W i jej polu dwFileAttributes będziesz miał atrybuty danej pozycji. Więcej na ten temat doczytaj na MSDNie i ogólnie pogoogluj sobie za przykładami użycia tych funkcji WinAPI pod Delphi. Skorzystanie z nich do podstawowych rzeczy nie powinno stanowaic żadnego problemu. Trzeba tylko używać TBrain :) A i dodam, że również korzystam z Delphi 7 i w przypadku skorzystania z tych funkcji, oczywiście nie ma problemów z błędnymi wartościami stałej faAnyFile i tego typu rzeczami.

0

Nie wiem, czy rozumiesz operacje dodawania i odejmowania, nie mogę tego wiedzieć. Nie wiem też, jaką masz wersję Delphi. Rzeczywiście, domyślnie przyjmuje się że D7, bo wiele osób wciąż jej używa. Nie rozumiem ostatniego zdania: podałem jaką flagę należy dodać do faAnyFile w Delphi 7. Jeśli masz XE3 to nie mam nic do powiedzenia.

A ja rozumiem że ty nie rozumiesz ironii. A co do Delphi to nie posiadam w ogóle.
Jeżeli nie rozumiesz to nie komentuj. Oczywiście minusować na oślep nikt tobie nie zabroni.

używam d7

To poszukaj czy d7 nie ma jakiegoś błędu który takie sprawy utrudnia, nikogo nie dziwi że 10+ letnie środowisko "ma problemy". Albo po prostu je zmień na coś nowszego np. Lazarusa.

0

póki co chce się nauczyć chociaż podstaw delphi w zadawalającym stopniu, a dopiero potem rozszerzać sobie o dodatkowe funkcję typu WinAPI :P

trochę pokombinowałem z tym i po małej zmianie:

  if (FindFirst(CurrentDir+'*.*', ((faSysFile + faDirectory) or (faDirectory + faHidden)), SRec) <> 0) Then
  Exit;

program zaczął działać i znajduje wszystkie pliki :) dzięki wszystkim za pomoc :)

0

Spoko, rób jak uważasz. Akurat lepiej używać tych funkcji, bo nie ma z nimi problemów. A akurat te mają niewiele parametrów i są banalne w użyciu. I nie są one dodatkowe, trzeba je traktować jako podstawe, z której później korzystają rozwiązania VCL.

1 użytkowników online, w tym zalogowanych: 0, gości: 1