0
# ShareFileClient - File Operations
1
2
The ShareFileClient provides comprehensive file management operations including upload/download, copying, range operations, metadata management, and advanced features like leasing and symbolic links.
3
4
## Import and Initialization
5
6
```python { .api }
7
from azure.storage.fileshare import ShareFileClient, ShareLeaseClient, ContentSettings
8
from azure.storage.fileshare import StorageStreamDownloader, Handle
9
from azure.core.credentials import AzureNamedKeyCredential
10
from typing import Optional, Union, Dict, Any, List, IO, AnyStr, Iterable, Tuple
11
```
12
13
## Constructor
14
15
```python { .api }
16
class ShareFileClient:
17
def __init__(
18
self,
19
account_url: str,
20
share_name: str,
21
file_path: str,
22
snapshot: Optional[Union[Dict[str, Any], str]] = None,
23
credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]] = None,
24
*,
25
token_intent: Optional[Literal['backup']] = None,
26
**kwargs: Any
27
) -> None:
28
"""
29
Create a ShareFileClient for a specific file.
30
31
Parameters:
32
account_url: The URL to the file service endpoint
33
share_name: Name of the share containing the file
34
file_path: Path to the file from share root
35
snapshot: Optional share snapshot identifier
36
credential: Authentication credential
37
token_intent: Specifies the intent for all requests when using TokenCredential authentication
38
**kwargs: Additional client configuration options
39
"""
40
```
41
42
## Class Methods
43
44
```python { .api }
45
@classmethod
46
def from_file_url(
47
cls,
48
file_url: str,
49
snapshot: Optional[Union[str, Dict[str, Any]]] = None,
50
credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]] = None,
51
**kwargs: Any
52
) -> ShareFileClient:
53
"""
54
Create ShareFileClient from file URL.
55
56
Parameters:
57
file_url: Complete URL to the file
58
snapshot: Optional share snapshot identifier
59
credential: Authentication credential
60
**kwargs: Additional client configuration options
61
62
Returns:
63
ShareFileClient: Configured client instance
64
"""
65
66
@classmethod
67
def from_connection_string(
68
cls,
69
conn_str: str,
70
share_name: str,
71
file_path: str,
72
snapshot: Optional[Union[str, Dict[str, Any]]] = None,
73
credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]] = None,
74
**kwargs: Any
75
) -> ShareFileClient:
76
"""
77
Create ShareFileClient from connection string.
78
79
Parameters:
80
conn_str: Azure Storage connection string
81
share_name: Name of the share
82
file_path: Path to the file from share root
83
snapshot: Optional share snapshot identifier
84
credential: Optional credential to override connection string auth
85
**kwargs: Additional client configuration options
86
87
Returns:
88
ShareFileClient: Configured client instance
89
"""
90
```
91
92
## File Lifecycle Operations
93
94
```python { .api }
95
def exists(
96
self,
97
**kwargs: Any
98
) -> bool:
99
"""
100
Returns True if the file exists, False otherwise.
101
102
Parameters:
103
timeout: Request timeout in seconds
104
105
Returns:
106
bool: True if file exists
107
"""
108
109
def create_file(
110
self,
111
size: int,
112
**kwargs: Any
113
) -> Dict[str, Any]:
114
"""
115
Creates a new file with the specified size.
116
117
Parameters:
118
size: Size of the file in bytes
119
content_settings: ContentSettings object with HTTP properties
120
metadata: Dict of name-value pairs for file metadata
121
file_attributes: File attributes (NTFSAttributes)
122
file_creation_time: Creation time for the file
123
file_last_write_time: Last write time for the file
124
file_permission: Security descriptor string or permission key
125
file_permission_key: Key for a previously created permission
126
lease_id: Required if file has an active lease
127
timeout: Request timeout in seconds
128
129
Returns:
130
Dict containing file creation response with ETag and properties
131
"""
132
133
def delete_file(
134
self,
135
**kwargs: Any
136
) -> None:
137
"""
138
Marks the specified file for deletion.
139
140
Parameters:
141
lease_id: Required if file has an active lease
142
timeout: Request timeout in seconds
143
"""
144
145
def rename_file(
146
self,
147
new_name: str,
148
**kwargs: Any
149
) -> ShareFileClient:
150
"""
151
Rename a file and return a client for the renamed file.
152
153
Parameters:
154
new_name: New path/name for the file
155
overwrite: Whether to overwrite existing file with same name
156
ignore_readonly: Whether to ignore readonly attribute on destination
157
file_permission: Security descriptor for the destination file
158
file_permission_key: Permission key for the destination file
159
timeout: Request timeout in seconds
160
161
Returns:
162
ShareFileClient: Client for the renamed file
163
"""
164
```
165
166
## File Upload Operations
167
168
```python { .api }
169
def upload_file(
170
self,
171
data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
172
length: Optional[int] = None,
173
**kwargs: Any
174
) -> Dict[str, Any]:
175
"""
176
Uploads a new file or overwrites an existing file.
177
178
Parameters:
179
data: File content to upload
180
length: Length of the data in bytes (required for streams)
181
overwrite: Whether to overwrite existing file (default: False)
182
max_concurrency: Number of parallel upload threads (default: 1)
183
content_settings: ContentSettings object with HTTP properties
184
metadata: Dict of name-value pairs for file metadata
185
validate_content: Whether to validate content with MD5 hash
186
file_attributes: File attributes (NTFSAttributes)
187
file_creation_time: Creation time for the file
188
file_last_write_time: Last write time for the file
189
file_permission: Security descriptor string or permission key
190
file_permission_key: Key for a previously created permission
191
lease_id: Required if file has an active lease
192
timeout: Request timeout in seconds
193
194
Returns:
195
Dict containing upload response with ETag and properties
196
"""
197
198
def upload_range(
199
self,
200
data: bytes,
201
offset: int,
202
length: int,
203
**kwargs: Any
204
) -> Dict[str, Any]:
205
"""
206
Upload a range of bytes to a file.
207
208
Parameters:
209
data: Bytes to upload
210
offset: Start position in the file
211
length: Number of bytes to upload
212
validate_content: Whether to validate content with MD5 hash
213
lease_id: Required if file has an active lease
214
timeout: Request timeout in seconds
215
216
Returns:
217
Dict containing range upload response
218
"""
219
220
def upload_range_from_url(
221
self,
222
source_url: str,
223
offset: int,
224
length: int,
225
source_offset: int,
226
**kwargs: Any
227
) -> Dict[str, Any]:
228
"""
229
Writes bytes from one Azure File endpoint into a range of another file.
230
231
Parameters:
232
source_url: URL of the source file (can include SAS token)
233
offset: Start position in the destination file
234
length: Number of bytes to copy
235
source_offset: Start position in the source file
236
timeout: Request timeout in seconds
237
238
Returns:
239
Dict containing range upload response
240
"""
241
```
242
243
## File Download Operations
244
245
```python { .api }
246
def download_file(
247
self,
248
offset: Optional[int] = None,
249
length: Optional[int] = None,
250
**kwargs: Any
251
) -> StorageStreamDownloader:
252
"""
253
Downloads a file to a StorageStreamDownloader.
254
255
Parameters:
256
offset: Start position to download from
257
length: Number of bytes to download
258
validate_content: Whether to validate content with MD5 hash
259
max_concurrency: Number of parallel download threads (default: 1)
260
lease_id: Required if file has an active lease
261
timeout: Request timeout in seconds
262
263
Returns:
264
StorageStreamDownloader: Stream object for downloading file content
265
"""
266
```
267
268
## File Copy Operations
269
270
```python { .api }
271
def start_copy_from_url(
272
self,
273
source_url: str,
274
**kwargs: Any
275
) -> Dict[str, Any]:
276
"""
277
Initiates copying data from a source URL into the file.
278
279
Parameters:
280
source_url: URL of the source file (can include SAS token)
281
metadata: Dict of name-value pairs for destination file metadata
282
file_permission: Security descriptor for destination file
283
file_permission_key: Permission key for destination file
284
ignore_readonly: Whether to ignore readonly attribute on destination
285
file_attributes: File attributes for destination file
286
file_creation_time: Creation time for destination file
287
file_last_write_time: Last write time for destination file
288
lease_id: Required if destination file has an active lease
289
timeout: Request timeout in seconds
290
291
Returns:
292
Dict containing copy operation details including copy_id
293
"""
294
295
def abort_copy(
296
self,
297
copy_id: Union[str, FileProperties],
298
**kwargs: Any
299
) -> None:
300
"""
301
Aborts a pending copy operation and leaves destination file with zero length.
302
303
Parameters:
304
copy_id: Copy identifier from start_copy_from_url response
305
lease_id: Required if file has an active lease
306
timeout: Request timeout in seconds
307
"""
308
```
309
310
## File Properties and Metadata
311
312
```python { .api }
313
def get_file_properties(
314
self,
315
**kwargs: Any
316
) -> FileProperties:
317
"""
318
Returns all user-defined metadata, standard HTTP properties, and system properties.
319
320
Parameters:
321
timeout: Request timeout in seconds
322
323
Returns:
324
FileProperties: Object containing all file properties
325
"""
326
327
def set_http_headers(
328
self,
329
content_settings: ContentSettings,
330
file_attributes: Optional[Union[str, NTFSAttributes]] = None,
331
file_creation_time: Optional[Union[str, datetime]] = None,
332
file_last_write_time: Optional[Union[str, datetime]] = None,
333
file_permission: Optional[str] = None,
334
permission_key: Optional[str] = None,
335
*,
336
lease: Optional[Union[ShareLeaseClient, str]] = None,
337
**kwargs: Any
338
) -> Dict[str, Any]:
339
"""
340
Sets system properties on the file.
341
342
Parameters:
343
content_settings: ContentSettings object with HTTP properties
344
file_attributes: File attributes (NTFSAttributes)
345
file_creation_time: Creation time for the file
346
file_last_write_time: Last write time for the file
347
file_permission: Security descriptor string or permission key
348
permission_key: Key for a previously created permission
349
lease: Required if file has an active lease
350
**kwargs: Additional keyword arguments
351
352
Returns:
353
Dict containing response with ETag and last modified time
354
"""
355
356
def set_file_metadata(
357
self,
358
metadata: Optional[Dict[str, Any]] = None,
359
**kwargs: Any
360
) -> Dict[str, Any]:
361
"""
362
Sets user-defined metadata for the file.
363
364
Parameters:
365
metadata: Dict of name-value pairs (keys must be valid metadata names)
366
lease_id: Required if file has an active lease
367
timeout: Request timeout in seconds
368
369
Returns:
370
Dict containing response with ETag and last modified time
371
"""
372
```
373
374
## Range Operations
375
376
```python { .api }
377
def get_ranges(
378
self,
379
offset: Optional[int] = None,
380
length: Optional[int] = None,
381
**kwargs: Any
382
) -> List[Dict[str, int]]:
383
"""
384
Returns the list of valid page ranges for a file.
385
386
Parameters:
387
offset: Start position to get ranges from
388
length: Number of bytes to get ranges for
389
lease_id: Required if file has an active lease
390
timeout: Request timeout in seconds
391
392
Returns:
393
List[Dict]: List of range dicts with 'start' and 'end' keys
394
"""
395
396
def get_ranges_diff(
397
self,
398
previous_sharesnapshot: Union[str, Dict[str, Any]],
399
offset: Optional[int] = None,
400
length: Optional[int] = None,
401
*,
402
include_renames: Optional[bool] = None,
403
**kwargs: Any
404
) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]:
405
"""
406
Returns ranges that differ between a previous snapshot and current file.
407
408
Parameters:
409
previous_sharesnapshot: Snapshot identifier to compare against
410
offset: Start position to compare from
411
length: Number of bytes to compare
412
include_renames: Whether to include renamed ranges in the response
413
**kwargs: Additional keyword arguments
414
415
Returns:
416
Tuple[List, List]: (changed_ranges, cleared_ranges)
417
"""
418
419
def clear_range(
420
self,
421
offset: int,
422
length: int,
423
**kwargs: Any
424
) -> Dict[str, Any]:
425
"""
426
Clears the specified range and releases space used in storage.
427
428
Parameters:
429
offset: Start position of the range to clear
430
length: Number of bytes to clear
431
lease_id: Required if file has an active lease
432
timeout: Request timeout in seconds
433
434
Returns:
435
Dict containing response with ETag and last modified time
436
"""
437
438
def resize_file(
439
self,
440
size: int,
441
**kwargs: Any
442
) -> Dict[str, Any]:
443
"""
444
Resizes a file to the specified size.
445
446
Parameters:
447
size: New size of the file in bytes
448
lease_id: Required if file has an active lease
449
timeout: Request timeout in seconds
450
451
Returns:
452
Dict containing response with ETag and last modified time
453
"""
454
```
455
456
## Handle Management
457
458
```python { .api }
459
def list_handles(
460
self,
461
**kwargs: Any
462
) -> ItemPaged[Handle]:
463
"""
464
Lists handles for the file.
465
466
Parameters:
467
marker: Continuation token for pagination
468
results_per_page: Maximum handles per page
469
timeout: Request timeout in seconds
470
471
Returns:
472
ItemPaged[Handle]: Paginated list of open handles
473
"""
474
475
def close_handle(
476
self,
477
handle: Union[str, Handle],
478
**kwargs: Any
479
) -> Dict[str, int]:
480
"""
481
Closes an open file handle.
482
483
Parameters:
484
handle: Handle ID string or Handle object to close
485
timeout: Request timeout in seconds
486
487
Returns:
488
Dict containing number of handles closed
489
"""
490
491
def close_all_handles(
492
self,
493
**kwargs: Any
494
) -> Dict[str, int]:
495
"""
496
Closes all handles for the file.
497
498
Parameters:
499
timeout: Request timeout in seconds
500
501
Returns:
502
Dict containing number of handles closed
503
"""
504
```
505
506
## Advanced File Operations
507
508
```python { .api }
509
def create_hardlink(
510
self,
511
target: str,
512
*,
513
lease: Optional[Union[ShareLeaseClient, str]] = None,
514
**kwargs: Any
515
) -> Dict[str, Any]:
516
"""
517
Create a hard link to an existing file.
518
519
Parameters:
520
target: Path for the new hard link
521
lease: Required if file has an active lease
522
**kwargs: Additional keyword arguments
523
524
Returns:
525
Dict[str, Any]: Response containing operation metadata
526
"""
527
528
def create_symlink(
529
self,
530
target: str,
531
*,
532
metadata: Optional[Dict[str, str]] = None,
533
**kwargs: Any
534
) -> Dict[str, Any]:
535
"""
536
Create a symbolic link to an existing file or directory.
537
538
Parameters:
539
target: Path to the target file or directory
540
metadata: Metadata for the symbolic link
541
**kwargs: Additional keyword arguments
542
543
Returns:
544
Dict[str, Any]: Response containing operation metadata
545
"""
546
547
def get_symlink(
548
self,
549
**kwargs: Any
550
) -> Dict[str, Any]:
551
"""
552
Get the target of a symbolic link.
553
554
Parameters:
555
**kwargs: Additional keyword arguments
556
557
Returns:
558
Dict[str, Any]: Response containing symlink target and metadata
559
"""
560
```
561
562
## Lease Management
563
564
```python { .api }
565
def acquire_lease(
566
self,
567
lease_id: Optional[str] = None,
568
**kwargs: Any
569
) -> ShareLeaseClient:
570
"""
571
Requests a new lease for the file.
572
573
Parameters:
574
lease_id: Proposed lease ID (UUID format)
575
lease_duration: Duration of the lease in seconds (-1 for infinite)
576
timeout: Request timeout in seconds
577
578
Returns:
579
ShareLeaseClient: Lease client for managing the lease
580
"""
581
```
582
583
## Properties
584
585
```python { .api }
586
@property
587
def url(self) -> str:
588
"""The full endpoint URL to the file."""
589
590
@property
591
def share_name(self) -> str:
592
"""The name of the share containing this file."""
593
594
@property
595
def file_path(self) -> str:
596
"""The path to the file with which to interact."""
597
598
@property
599
def snapshot(self) -> Optional[str]:
600
"""An optional share snapshot on which to operate."""
601
602
@property
603
def account_name(self) -> str:
604
"""The storage account name."""
605
606
@property
607
def credential(self) -> Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]:
608
"""The credential used to authenticate."""
609
```
610
611
## Usage Examples
612
613
### Basic File Operations
614
615
```python { .api }
616
from azure.storage.fileshare import ShareFileClient, ContentSettings
617
from azure.core.credentials import AzureNamedKeyCredential
618
619
# Initialize file client
620
credential = AzureNamedKeyCredential("myaccount", "mykey")
621
file_client = ShareFileClient(
622
account_url="https://myaccount.file.core.windows.net",
623
share_name="documents",
624
file_path="reports/monthly_report.pdf",
625
credential=credential
626
)
627
628
# Check if file exists
629
if file_client.exists():
630
print("File already exists")
631
else:
632
print("File does not exist")
633
634
# Upload a new file
635
with open("local_report.pdf", "rb") as data:
636
upload_response = file_client.upload_file(
637
data=data,
638
overwrite=True,
639
content_settings=ContentSettings(
640
content_type="application/pdf",
641
content_disposition="attachment; filename=monthly_report.pdf"
642
),
643
metadata={"department": "finance", "month": "january", "year": "2024"}
644
)
645
print(f"File uploaded with ETag: {upload_response['etag']}")
646
```
647
648
### File Download and Content Processing
649
650
```python { .api }
651
# Download entire file
652
download_stream = file_client.download_file()
653
654
# Method 1: Download to bytes
655
file_content = download_stream.readall()
656
print(f"Downloaded {len(file_content)} bytes")
657
658
# Method 2: Download to local file
659
with open("downloaded_report.pdf", "wb") as file_handle:
660
download_stream.readinto(file_handle)
661
662
# Method 3: Download with parallel connections
663
download_stream = file_client.download_file(max_concurrency=4)
664
content = download_stream.content_as_bytes(max_concurrency=4)
665
666
# Partial download (range)
667
partial_stream = file_client.download_file(offset=0, length=1024) # First 1KB
668
first_chunk = partial_stream.readall()
669
670
# Download and process as text
671
text_file_client = ShareFileClient(
672
account_url="https://myaccount.file.core.windows.net",
673
share_name="documents",
674
file_path="config.txt",
675
credential=credential
676
)
677
678
text_stream = text_file_client.download_file()
679
text_content = text_stream.content_as_text(encoding="utf-8")
680
print(f"File content:\n{text_content}")
681
```
682
683
### Advanced Upload Scenarios
684
685
```python { .api }
686
from azure.storage.fileshare import NTFSAttributes
687
from datetime import datetime, timezone
688
689
# Large file upload with progress tracking
690
def upload_large_file(file_client, local_path, chunk_size=4*1024*1024):
691
"""Upload large file in chunks with progress."""
692
import os
693
694
file_size = os.path.getsize(local_path)
695
696
# Create empty file first
697
file_client.create_file(file_size)
698
699
with open(local_path, "rb") as file_handle:
700
offset = 0
701
while offset < file_size:
702
chunk = file_handle.read(chunk_size)
703
if not chunk:
704
break
705
706
file_client.upload_range(
707
data=chunk,
708
offset=offset,
709
length=len(chunk)
710
)
711
712
offset += len(chunk)
713
progress = (offset / file_size) * 100
714
print(f"Upload progress: {progress:.1f}%")
715
716
# Upload with custom attributes
717
upload_response = file_client.upload_file(
718
data=b"Sample file content",
719
overwrite=True,
720
file_attributes=NTFSAttributes.Archive | NTFSAttributes.ReadOnly,
721
file_creation_time=datetime(2024, 1, 1, tzinfo=timezone.utc),
722
file_last_write_time=datetime.now(timezone.utc),
723
validate_content=True # Validates MD5 hash
724
)
725
```
726
727
### File Copy and Backup Operations
728
729
```python { .api }
730
# Copy file from another Azure file share
731
source_url = "https://sourceaccount.file.core.windows.net/source-share/file.txt"
732
source_sas = "?sp=r&st=2024-01-01T00:00:00Z&se=2024-12-31T23:59:59Z&sv=2021-06-08&sr=f&sig=..."
733
734
copy_response = file_client.start_copy_from_url(
735
source_url=source_url + source_sas,
736
metadata={"copied_from": "backup_share", "copy_date": datetime.now().isoformat()}
737
)
738
739
copy_id = copy_response['copy_id']
740
print(f"Copy started with ID: {copy_id}")
741
742
# Monitor copy progress
743
import time
744
while True:
745
properties = file_client.get_file_properties()
746
copy_status = properties.copy.status
747
print(f"Copy status: {copy_status}")
748
749
if copy_status == 'success':
750
print("Copy completed successfully")
751
break
752
elif copy_status == 'failed':
753
print(f"Copy failed: {properties.copy.status_description}")
754
break
755
756
time.sleep(5) # Check again in 5 seconds
757
758
# Copy between ranges
759
source_file_client = ShareFileClient(
760
account_url="https://myaccount.file.core.windows.net",
761
share_name="source",
762
file_path="large_file.bin",
763
credential=credential
764
)
765
766
# Copy specific range from source to destination
767
file_client.upload_range_from_url(
768
source_url=source_file_client.url + "?" + sas_token,
769
offset=0, # Destination offset
770
length=1024*1024, # 1MB
771
source_offset=5*1024*1024 # Start from 5MB in source
772
)
773
```
774
775
### Range Operations and File Manipulation
776
777
```python { .api }
778
# Get file ranges (for sparse files)
779
ranges = file_client.get_ranges()
780
print("File ranges:")
781
for range_info in ranges:
782
print(f" {range_info['start']}-{range_info['end']} ({range_info['end'] - range_info['start'] + 1} bytes)")
783
784
# Clear a range (create a hole in the file)
785
file_client.clear_range(offset=1024, length=2048)
786
787
# Compare with snapshot
788
snapshot_client = ShareFileClient(
789
account_url="https://myaccount.file.core.windows.net",
790
share_name="documents",
791
file_path="reports/monthly_report.pdf",
792
snapshot="2024-01-01T00:00:00Z",
793
credential=credential
794
)
795
796
changed_ranges, cleared_ranges = file_client.get_ranges_diff(
797
previous_sharesnapshot="2024-01-01T00:00:00Z"
798
)
799
print(f"Changed ranges: {len(changed_ranges)}")
800
print(f"Cleared ranges: {len(cleared_ranges)}")
801
802
# Resize file
803
current_size = file_client.get_file_properties().size
804
new_size = current_size + 1024*1024 # Add 1MB
805
file_client.resize_file(new_size)
806
print(f"File resized from {current_size} to {new_size} bytes")
807
```
808
809
### Metadata and Properties Management
810
811
```python { .api }
812
# Get comprehensive file properties
813
properties = file_client.get_file_properties()
814
print(f"File: {properties.name}")
815
print(f"Size: {properties.size} bytes")
816
print(f"Content type: {properties.content_settings.content_type}")
817
print(f"Last modified: {properties.last_modified}")
818
print(f"ETag: {properties.etag}")
819
print(f"Metadata: {properties.metadata}")
820
print(f"Attributes: {properties.file_attributes}")
821
print(f"Creation time: {properties.creation_time}")
822
823
# Update HTTP headers
824
file_client.set_http_headers(
825
content_settings=ContentSettings(
826
content_type="application/json",
827
content_encoding="gzip",
828
content_language="en-US",
829
cache_control="max-age=3600"
830
)
831
)
832
833
# Update metadata
834
file_client.set_file_metadata({
835
"processed": "true",
836
"processing_date": datetime.now().isoformat(),
837
"version": "2.1",
838
"checksum": "abc123def456"
839
})
840
```
841
842
### Handle Management for Open Files
843
844
```python { .api }
845
# List open handles on the file
846
handles = list(file_client.list_handles())
847
print(f"File has {len(handles)} open handle(s)")
848
849
for handle in handles:
850
print(f"Handle {handle.id}:")
851
print(f" Client: {handle.client_name} ({handle.client_ip})")
852
print(f" Session: {handle.session_id}")
853
print(f" Opened: {handle.open_time}")
854
print(f" Access: {handle.access_rights}")
855
856
# Close specific handle (useful for releasing locks)
857
if handles:
858
result = file_client.close_handle(handles[0])
859
print(f"Closed {result['closed_handles_count']} handle(s)")
860
861
# Close all handles (useful for maintenance)
862
result = file_client.close_all_handles()
863
print(f"Closed {result['closed_handles_count']} total handle(s)")
864
```
865
866
### Symbolic Links and Hard Links
867
868
```python { .api }
869
# Create symbolic link
870
symlink_client = file_client.create_symlink(
871
target_path="../../shared/template.docx",
872
file_attributes=NTFSAttributes.ReparsePoint
873
)
874
print(f"Symbolic link created: {symlink_client.file_path}")
875
876
# Get symlink target
877
target = symlink_client.get_symlink()
878
print(f"Symlink points to: {target}")
879
880
# Create hard link (multiple names for same file)
881
hardlink_client = file_client.create_hardlink("backup_copy.pdf")
882
print(f"Hard link created: {hardlink_client.file_path}")
883
884
# Both clients point to the same file content
885
original_props = file_client.get_file_properties()
886
hardlink_props = hardlink_client.get_file_properties()
887
print(f"Same file ID: {original_props.file_id == hardlink_props.file_id}")
888
```
889
890
### Lease Management for Exclusive Access
891
892
```python { .api }
893
# Acquire lease for exclusive access
894
lease_client = file_client.acquire_lease(lease_duration=60) # 60 second lease
895
print(f"Lease acquired: {lease_client.id}")
896
897
try:
898
# Perform operations with lease
899
file_client.set_file_metadata(
900
{"locked_by": "batch_process", "lock_time": datetime.now().isoformat()},
901
lease_id=lease_client.id
902
)
903
904
# Upload new content (requires lease)
905
file_client.upload_file(
906
data=b"Updated content with exclusive access",
907
overwrite=True,
908
lease_id=lease_client.id
909
)
910
911
finally:
912
# Always release the lease
913
lease_client.release()
914
print("Lease released")
915
```
916
917
### Error Handling and Recovery
918
919
```python { .api }
920
from azure.core.exceptions import ResourceExistsError, ResourceNotFoundError, HttpResponseError
921
922
# Safe file operations with error handling
923
try:
924
# Try to upload file
925
file_client.upload_file(data=b"content", overwrite=False)
926
except ResourceExistsError:
927
print("File exists, checking if update is needed...")
928
properties = file_client.get_file_properties()
929
if properties.size == 0:
930
# Empty file, safe to overwrite
931
file_client.upload_file(data=b"content", overwrite=True)
932
else:
933
print("File has content, skipping upload")
934
935
# Handle copy operation errors
936
try:
937
copy_response = file_client.start_copy_from_url(source_url)
938
copy_id = copy_response['copy_id']
939
940
# Monitor and handle copy failure
941
properties = file_client.get_file_properties()
942
if properties.copy.status == 'failed':
943
print(f"Copy failed: {properties.copy.status_description}")
944
file_client.abort_copy(copy_id)
945
946
except HttpResponseError as e:
947
if e.error_code == "CannotVerifyCopySource":
948
print("Source file not accessible or SAS token expired")
949
else:
950
print(f"Copy operation failed: {e.message}")
951
952
# Retry logic for transient failures
953
import time
954
from azure.core.exceptions import ServiceRequestError
955
956
def upload_with_retry(file_client, data, max_retries=3):
957
"""Upload with exponential backoff retry."""
958
for attempt in range(max_retries):
959
try:
960
return file_client.upload_file(data, overwrite=True)
961
except ServiceRequestError as e:
962
if attempt < max_retries - 1:
963
wait_time = 2 ** attempt # Exponential backoff
964
print(f"Upload failed, retrying in {wait_time} seconds...")
965
time.sleep(wait_time)
966
else:
967
raise
968
```
969
970
The ShareFileClient provides comprehensive file management capabilities, enabling efficient file operations, content management, and advanced features like leasing and symbolic links for Azure File Share storage.