You have misunderstood how Subscription and add work.
When you subscribe to something, you get a Subscription object, to which you can call unsubscribe(). This is fine. However, you haven't assigned the value correctly. You assigned the Subscription to const sub, which you then pass in as the completion block to add.
Consider Subscription.add like a finally block of a try/catch. No matter what the result of the Subscription, when it is complete, the block passed to add will execute. Use this for any cleanup tasks.
subscriptions: Subscriptions[] = [];
ngOnDestroy() {
   subscriptions.forEach((sub) => sub.unsubscribe());
}
deleteFile(id: any) {
   const sub = this.fileCabinetService.deleteFile(id).subscribe(...);
   this.subscriptions.push(sub);
   sub.add(() => this.subscriptions.remove(sub));
}
To answer your question about when to unsubscribe, it really depends on what deleteFile does. If the deleteFile method internally signals with a value (or a set of values) and then is completed, the subscription is terminated automatically. If it is not completed and left dangling, then your subscription will persist.
Consider the scenario of:
WallClock.subscribe((time) => console.log(time));
This Subscription will never be terminated because time (presumably) will continue indefinitely. Instead, you will want to manually control when this is terminated. You can do this in a few ways:
/* Get the current time, but don't bother listening to updates. */
WallClock.pipe(take(1)).subscribe((time) => console.log(time));
/* Continually update with the current time as long as the component is on screen
   — Requires setting `this.staySubscribed = false` when you're leaving */
WallClock.pipe(takeWhile(() => this.staySubscribed)).subscribe((time) => console.log(time));
/* Continually update until you remember to unsubscribe
   — Requires remembering to unsubscribe and can get verbose with multiple subscriptions
   - Call `this.subscription.unsubscribe()` later */
this.subscription = WallClock.subscribe((time) => console.log(time));
If your deleteFile operates like this and continually reports values without a definite completion condition, you should make sure to terminate the subscription in some way. It is likely the case (based on the name of the function) that this is a self-terminating Subscription that will not require anything on your part. If you want to be really safe, the pipe(take(1)) will ensure it for you.